diff --git a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java
index f66ee3245e..db3794c39f 100644
--- a/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java
+++ b/plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgCGIServlet.java
@@ -44,8 +44,8 @@ import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.util.AssertUtil;
-import sonia.scm.web.cgi.AbstractCGIServlet;
-import sonia.scm.web.cgi.EnvList;
+import sonia.scm.web.cgi.CGIExecutor;
+import sonia.scm.web.cgi.CGIExecutorFactory;
//~--- JDK imports ------------------------------------------------------------
@@ -56,14 +56,16 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
-public class HgCGIServlet extends AbstractCGIServlet
+public class HgCGIServlet extends HttpServlet
{
/** Field description */
@@ -90,16 +92,20 @@ public class HgCGIServlet extends AbstractCGIServlet
*
*
*
+ *
+ * @param cgiExecutorFactory
* @param configuration
* @param repositoryManager
* @param handler
*/
@Inject
- public HgCGIServlet(ScmConfiguration configuration,
+ public HgCGIServlet(CGIExecutorFactory cgiExecutorFactory,
+ ScmConfiguration configuration,
RepositoryManager repositoryManager,
HgRepositoryHandler handler)
{
- super(configuration);
+ this.cgiExecutorFactory = cgiExecutorFactory;
+ this.configuration = configuration;
this.repositoryManager = repositoryManager;
this.handler = handler;
}
@@ -124,18 +130,16 @@ public class HgCGIServlet extends AbstractCGIServlet
*
*
* @param request
- * @param baseEnvironment
- *
- * @return
+ * @param response
*
+ * @throws IOException
* @throws ServletException
*/
@Override
- protected EnvList createRequestEnvironment(HttpServletRequest request,
- EnvList baseEnvironment)
- throws ServletException
+ protected void service(HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException
{
- EnvList list = new EnvList(baseEnvironment);
Repository repository = getRepository(request);
if (repository == null)
@@ -145,10 +149,6 @@ public class HgCGIServlet extends AbstractCGIServlet
String name = repository.getName();
File directory = handler.getDirectory(repository);
-
- list.set(ENV_REPOSITORY_PATH, directory.getAbsolutePath());
- list.set(ENV_REPOSITORY_NAME, name);
-
String pythonPath = "";
HgConfig config = handler.getConfig();
@@ -162,9 +162,22 @@ public class HgCGIServlet extends AbstractCGIServlet
}
}
- list.set(ENV_PYTHON_PATH, pythonPath);
+ CGIExecutor executor = cgiExecutorFactory.createExecutor(configuration,
+ getServletContext(), request, response);
- return list;
+ executor.getEnvironment().set(ENV_REPOSITORY_NAME, name);
+ executor.getEnvironment().set(ENV_REPOSITORY_PATH,
+ directory.getAbsolutePath());
+ executor.getEnvironment().set(ENV_PYTHON_PATH, pythonPath);
+
+ String interpreter = getInterpreter();
+
+ if (interpreter != null)
+ {
+ executor.setInterpreter(interpreter);
+ }
+
+ executor.execute(command.getAbsolutePath());
}
//~--- get methods ----------------------------------------------------------
@@ -175,8 +188,7 @@ public class HgCGIServlet extends AbstractCGIServlet
*
* @return
*/
- @Override
- protected String getCmdPrefix()
+ private String getInterpreter()
{
HgConfig config = handler.getConfig();
@@ -192,24 +204,6 @@ public class HgCGIServlet extends AbstractCGIServlet
return python;
}
- /**
- * Method description
- *
- *
- * @param req
- *
- * @return
- *
- * @throws IOException
- * @throws ServletException
- */
- @Override
- protected File getCommand(HttpServletRequest req)
- throws ServletException, IOException
- {
- return command;
- }
-
/**
* Method description
*
@@ -218,7 +212,7 @@ public class HgCGIServlet extends AbstractCGIServlet
*
* @return
*/
- protected Repository getRepository(HttpServletRequest request)
+ private Repository getRepository(HttpServletRequest request)
{
Repository repository = null;
String uri = request.getRequestURI();
@@ -252,9 +246,15 @@ public class HgCGIServlet extends AbstractCGIServlet
//~--- fields ---------------------------------------------------------------
+ /** Field description */
+ private CGIExecutorFactory cgiExecutorFactory;
+
/** Field description */
private File command;
+ /** Field description */
+ private ScmConfiguration configuration;
+
/** Field description */
private HgRepositoryHandler handler;
diff --git a/scm-core/src/main/java/sonia/scm/util/IOUtil.java b/scm-core/src/main/java/sonia/scm/util/IOUtil.java
index 9c9afa55bb..d7cca44d7c 100644
--- a/scm-core/src/main/java/sonia/scm/util/IOUtil.java
+++ b/scm-core/src/main/java/sonia/scm/util/IOUtil.java
@@ -118,12 +118,14 @@ public class IOUtil
*
* @param reader
* @param writer
+ * @param bufferSize
*
* @throws IOException
*/
- public static void copy(Reader reader, Writer writer) throws IOException
+ public static void copy(Reader reader, Writer writer, int bufferSize)
+ throws IOException
{
- char[] buffer = new char[0xFFFF];
+ char[] buffer = new char[bufferSize];
for (int len; (len = reader.read(buffer)) != -1; )
{
@@ -131,6 +133,20 @@ public class IOUtil
}
}
+ /**
+ * Method description
+ *
+ *
+ * @param reader
+ * @param writer
+ *
+ * @throws IOException
+ */
+ public static void copy(Reader reader, Writer writer) throws IOException
+ {
+ copy(reader, writer, 0xFFFF);
+ }
+
/**
* Method description
*
@@ -142,12 +158,30 @@ public class IOUtil
*/
public static void copy(InputStream in, OutputStream out) throws IOException
{
- byte[] buffer = new byte[0xFFFF];
+ copy(in, out, 0xFFFF);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param in
+ * @param out
+ * @param bufferSize
+ *
+ * @throws IOException
+ */
+ public static void copy(InputStream in, OutputStream out, int bufferSize)
+ throws IOException
+ {
+ byte[] buffer = new byte[bufferSize];
for (int len; (len = in.read(buffer)) != -1; )
{
out.write(buffer, 0, len);
}
+
+ out.flush();
}
/**
diff --git a/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIExecutor.java b/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIExecutor.java
new file mode 100644
index 0000000000..10ef6981d6
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIExecutor.java
@@ -0,0 +1,158 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.web.cgi;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public abstract class AbstractCGIExecutor implements CGIExecutor
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public int getBufferSize()
+ {
+ return bufferSize;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public EnvList getEnvironment()
+ {
+ return environment;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public String getInterpreter()
+ {
+ return interpreter;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ @Override
+ public File getWorkDirectory()
+ {
+ return workDirectory;
+ }
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param bufferSize
+ */
+ @Override
+ public void setBufferSize(int bufferSize)
+ {
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param environment
+ */
+ @Override
+ public void setEnvironment(EnvList environment)
+ {
+ this.environment = environment;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param interpreter
+ */
+ @Override
+ public void setInterpreter(String interpreter)
+ {
+ this.interpreter = interpreter;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param workDirectory
+ */
+ @Override
+ public void setWorkDirectory(File workDirectory)
+ {
+ this.workDirectory = workDirectory;
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ protected int bufferSize;
+
+ /** Field description */
+ protected EnvList environment;
+
+ /** Field description */
+ protected String interpreter;
+
+ /** Field description */
+ protected File workDirectory;
+}
diff --git a/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java b/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java
index 1693bde3eb..4db1645519 100644
--- a/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java
+++ b/scm-core/src/main/java/sonia/scm/web/cgi/AbstractCGIServlet.java
@@ -53,7 +53,9 @@ import javax.servlet.http.HttpServletResponse;
/**
*
* @author Sebastian Sdorra
+ * @deprecated use {@link CGIExecutorFactory}
*/
+@Deprecated
public abstract class AbstractCGIServlet extends HttpServlet
{
diff --git a/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutor.java b/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutor.java
new file mode 100644
index 0000000000..ee6802d54c
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutor.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.web.cgi;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public interface CGIExecutor
+{
+
+ /** Field description */
+ public static final String ENV_AUTH_TYPE = "AUTH_TYPE";
+
+ /** Field description */
+ public static final String ENV_CONTENT_LENGTH = "CONTENT_LENGTH";
+
+ /** Field description */
+ public static final String ENV_CONTENT_TYPE = "CONTENT_TYPE";
+
+ /** Field description */
+ public static final String ENV_GATEWAY_INTERFACE = "GATEWAY_INTERFACE";
+
+ /** Field description */
+ public static final String ENV_HTTPS = "HTTPS";
+
+ /** Field description */
+ public static final String ENV_HTTPS_VALUE_OFF = "OFF";
+
+ /** Field description */
+ public static final String ENV_HTTPS_VALUE_ON = "ON";
+
+ /** Field description */
+ public static final String ENV_HTTP_HEADER_PREFIX = "HTTP_";
+
+ /** Field description */
+ public static final String ENV_PATH_INFO = "PATH_INFO";
+
+ /** Field description */
+ public static final String ENV_PATH_TRANSLATED = "PATH_TRANSLATED";
+
+ /** Field description */
+ public static final String ENV_QUERY_STRING = "QUERY_STRING";
+
+ /** Field description */
+ public static final String ENV_REMOTE_ADDR = "REMOTE_ADDR";
+
+ /** Field description */
+ public static final String ENV_REMOTE_HOST = "REMOTE_HOST";
+
+ /** Field description */
+ public static final String ENV_REMOTE_USER = "REMOTE_USER";
+
+ /** Field description */
+ public static final String ENV_REQUEST_METHOD = "REQUEST_METHOD";
+
+ /** Field description */
+ public static final String ENV_SCRIPT_FILENAME = "SCRIPT_FILENAME";
+
+ /** Field description */
+ public static final String ENV_SCRIPT_NAME = "SCRIPT_NAME";
+
+ /** Field description */
+ public static final String ENV_SERVER_NAME = "SERVER_NAME";
+
+ /** Field description */
+ public static final String ENV_SERVER_PORT = "SERVER_PORT";
+
+ /** Field description */
+ public static final String ENV_SERVER_PROTOCOL = "SERVER_PROTOCOL";
+
+ /** Field description */
+ public static final String ENV_SERVER_SOFTWARE = "SERVER_SOFTWARE";
+
+ /** Field description */
+ public static final String RESPONSE_HEADER_HTTP_PREFIX = "HTTP";
+
+ /** Field description */
+ public static final String RESPONSE_HEADER_LOCATION = "Location";
+
+ /** Field description */
+ public static final String RESPONSE_HEADER_STATUS = "Status";
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param cmd
+ *
+ * @throws IOException
+ * @throws ServletException
+ */
+ public void execute(String cmd) throws IOException, ServletException;
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public int getBufferSize();
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public EnvList getEnvironment();
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public String getInterpreter();
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ public File getWorkDirectory();
+
+ //~--- set methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param bufferSize
+ */
+ public void setBufferSize(int bufferSize);
+
+ /**
+ * Method description
+ *
+ *
+ * @param environment
+ */
+ public void setEnvironment(EnvList environment);
+
+ /**
+ * Method description
+ *
+ *
+ * @param interpreter
+ */
+ public void setInterpreter(String interpreter);
+
+ /**
+ * Method description
+ *
+ *
+ * @param workDirectory
+ */
+ public void setWorkDirectory(File workDirectory);
+}
diff --git a/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutorFactory.java b/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutorFactory.java
new file mode 100644
index 0000000000..0ef14a9db5
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/web/cgi/CGIExecutorFactory.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.web.cgi;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import sonia.scm.config.ScmConfiguration;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public interface CGIExecutorFactory
+{
+
+ /**
+ * Method description
+ *
+ *
+ *
+ * @param configuration
+ * @param context
+ * @param request
+ * @param response
+ *
+ * @return
+ */
+ public CGIExecutor createExecutor(ScmConfiguration configuration,
+ ServletContext context,
+ HttpServletRequest request,
+ HttpServletResponse response);
+}
diff --git a/scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java b/scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java
index 5623f9df7d..9554aab8e1 100644
--- a/scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java
+++ b/scm-core/src/main/java/sonia/scm/web/cgi/CGIRunner.java
@@ -59,8 +59,9 @@ import javax.servlet.http.HttpServletResponse;
* Based on org.eclipse.jetty.servlets.CGI
*
* @author Sebastian Sdorra
- *
+ * @deprecated use {@link CGIExecutorFactory}
*/
+@Deprecated
public class CGIRunner
{
@@ -335,11 +336,7 @@ public class CGIRunner
}
finally
{
- if (os != null)
- {
- IOUtil.close(os);
- }
-
+ IOUtil.close(os);
os = null;
p.destroy();
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index b93f6918c8..d70f6ab7b1 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -278,7 +278,7 @@
1.11
1.0-beta-7
3.0.3
- Tomcat60
+ gfv3ee6
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
index 75e8c9a164..92dbfa9a6a 100644
--- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java
@@ -70,6 +70,8 @@ import sonia.scm.template.TemplateServlet;
import sonia.scm.user.UserManager;
import sonia.scm.user.xml.XmlUserManager;
import sonia.scm.util.DebugServlet;
+import sonia.scm.web.cgi.CGIExecutorFactory;
+import sonia.scm.web.cgi.DefaultCGIExecutorFactory;
import sonia.scm.web.security.AuthenticationManager;
import sonia.scm.web.security.BasicSecurityContext;
import sonia.scm.web.security.ChainAuthenticatonManager;
@@ -215,8 +217,9 @@ public class ScmServletModule extends ServletModule
bind(RepositoryManager.class).to(XmlRepositoryManager.class);
bind(UserManager.class).to(XmlUserManager.class);
bind(GroupManager.class).to(XmlGroupManager.class);
+ bind(CGIExecutorFactory.class).to(DefaultCGIExecutorFactory.class);
- // filter(PATTERN_RESTAPI).through(LoggingFilter.class);
+ // filter("/hg/*").through(LoggingFilter.class);
/*
* filter(PATTERN_PAGE,
diff --git a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java
new file mode 100644
index 0000000000..668c9349fb
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutor.java
@@ -0,0 +1,487 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.web.cgi;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import sonia.scm.SCMContext;
+import sonia.scm.config.ScmConfiguration;
+import sonia.scm.util.HttpUtil;
+import sonia.scm.util.IOUtil;
+import sonia.scm.util.Util;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import java.util.Enumeration;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class DefaultCGIExecutor extends AbstractCGIExecutor
+{
+
+ /** Field description */
+ public static final String CGI_VERSION = "CGI/1.1";
+
+ /** Field description */
+ public static final int DEFAULT_BUFFER_SIZE = 16264;
+
+ /** Field description */
+ private static final String SERVER_SOFTWARE_PREFIX = "scm-manager/";
+
+ /** the logger for DefaultCGIExecutor */
+ private static final Logger logger =
+ LoggerFactory.getLogger(DefaultCGIExecutor.class);
+
+ //~--- constructors ---------------------------------------------------------
+
+ /**
+ * Constructs ...
+ *
+ *
+ * @param configuration
+ * @param context
+ * @param request
+ * @param response
+ */
+ public DefaultCGIExecutor(ScmConfiguration configuration,
+ ServletContext context, HttpServletRequest request,
+ HttpServletResponse response)
+ {
+ this.configuration = configuration;
+ this.context = context;
+ this.request = request;
+ this.response = response;
+
+ // set default values
+ this.bufferSize = DEFAULT_BUFFER_SIZE;
+ this.environment = createEnvironment();
+ }
+
+ //~--- methods --------------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ *
+ *
+ * @param cmd
+ *
+ * @throws IOException
+ */
+ @Override
+ public void execute(String cmd) throws IOException
+ {
+ File command = new File(cmd);
+ EnvList env = new EnvList(environment);
+
+ if (workDirectory == null)
+ {
+ workDirectory = command.getParentFile();
+ }
+
+ String path = command.getAbsolutePath();
+ String pathTranslated = request.getPathTranslated();
+
+ if (Util.isEmpty(pathTranslated))
+ {
+ pathTranslated = path;
+ }
+
+ env.set(ENV_PATH_TRANSLATED, pathTranslated);
+
+ String execCmd = path;
+
+ if ((execCmd.charAt(0) != '"') && (execCmd.indexOf(" ") >= 0))
+ {
+ execCmd = "\"" + execCmd + "\"";
+ }
+
+ if (interpreter != null)
+ {
+ execCmd = interpreter + " " + execCmd;
+ }
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("execute cgi: {}", execCmd);
+
+ if (logger.isTraceEnabled())
+ {
+ logger.trace(environment.toString());
+ }
+ }
+
+ Process p = Runtime.getRuntime().exec(execCmd, environment.getEnvArray(),
+ workDirectory);
+
+ execute(p);
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @return
+ */
+ private EnvList createEnvironment()
+ {
+ String pathInfo = request.getPathInfo();
+ int serverPort = HttpUtil.getServerPort(configuration, request);
+ String scriptName = request.getRequestURI().substring(0,
+ request.getRequestURI().length() - pathInfo.length());
+ String scriptPath = context.getRealPath(scriptName);
+ int len = request.getContentLength();
+
+ if (len < 0)
+ {
+ len = 0;
+ }
+
+ EnvList env = new EnvList();
+
+ env.set(ENV_AUTH_TYPE, request.getAuthType());
+ env.set(ENV_CONTENT_LENGTH, Integer.toString(len));
+ env.set(ENV_CONTENT_TYPE, request.getContentType());
+ env.set(ENV_GATEWAY_INTERFACE, CGI_VERSION);
+ env.set(ENV_PATH_INFO, pathInfo);
+ env.set(ENV_QUERY_STRING, request.getQueryString());
+ env.set(ENV_REMOTE_ADDR, request.getRemoteAddr());
+ env.set(ENV_REMOTE_HOST, request.getRemoteHost());
+
+ // The identity information reported about the connection by a
+ // RFC 1413 [11] request to the remote agent, if
+ // available. Servers MAY choose not to support this feature, or
+ // not to request the data for efficiency reasons.
+ // "REMOTE_IDENT" => "NYI"
+ env.set(ENV_REMOTE_USER, request.getRemoteUser());
+ env.set(ENV_REQUEST_METHOD, request.getMethod());
+ env.set(ENV_SCRIPT_NAME, scriptName);
+ env.set(ENV_SCRIPT_FILENAME, scriptPath);
+ env.set(ENV_SERVER_NAME, request.getServerName());
+ env.set(ENV_SERVER_PORT, Integer.toString(serverPort));
+ env.set(ENV_SERVER_PROTOCOL, request.getProtocol());
+ env.set(
+ ENV_SERVER_SOFTWARE,
+ SERVER_SOFTWARE_PREFIX.concat(SCMContext.getContext().getVersion()));
+
+ Enumeration enm = request.getHeaderNames();
+
+ while (enm.hasMoreElements())
+ {
+ String name = (String) enm.nextElement();
+ String value = request.getHeader(name);
+
+ env.set(ENV_HTTP_HEADER_PREFIX + name.toUpperCase().replace('-', '_'),
+ value);
+ }
+
+ // these extra ones were from printenv on www.dev.nomura.co.uk
+ env.set(ENV_HTTPS, (request.isSecure()
+ ? ENV_HTTPS_VALUE_ON
+ : ENV_HTTPS_VALUE_OFF));
+
+ return env;
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param process
+ *
+ * @throws IOException
+ */
+ private void execute(Process process) throws IOException
+ {
+ InputStream processIS = null;
+ InputStream processES = null;
+
+ try
+ {
+ processIS = process.getInputStream();
+ processES = process.getErrorStream();
+ processServletInput(process);
+ processProcessInputStream(processIS);
+ processErrorStream(processES);
+ waitForFinish(process);
+ }
+ finally
+ {
+ IOUtil.close(processIS);
+ IOUtil.close(processES);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param is
+ *
+ *
+ * @throws IOException
+ */
+ private void parseHeaders(InputStream is) throws IOException
+ {
+ String line = null;
+
+ while ((line = getTextLineFromStream(is)).length() > 0)
+ {
+ if (logger.isTraceEnabled())
+ {
+ logger.trace(" ".concat(line));
+ }
+
+ if (!line.startsWith(RESPONSE_HEADER_HTTP_PREFIX))
+ {
+ int k = line.indexOf(':');
+
+ if (k > 0)
+ {
+ String key = line.substring(0, k).trim();
+ String value = line.substring(k + 1).trim();
+
+ if (RESPONSE_HEADER_LOCATION.equals(key))
+ {
+ response.sendRedirect(response.encodeRedirectURL(value));
+ }
+ else if (RESPONSE_HEADER_STATUS.equals(key))
+ {
+ String[] token = value.split(" ");
+ int status = Integer.parseInt(token[0]);
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("CGI returned with status {}", status);
+ }
+
+ if (status < 304)
+ {
+ response.setStatus(status);
+ }
+ else
+ {
+ response.sendError(status);
+ }
+ }
+ else
+ {
+
+ // add remaining header items to our response header
+ response.addHeader(key, value);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param in
+ *
+ * @throws IOException
+ */
+ private void processErrorStream(InputStream in) throws IOException
+ {
+ BufferedReader reader = null;
+
+ try
+ {
+ reader = new BufferedReader(new InputStreamReader(in));
+
+ StringBuilder error = new StringBuilder();
+ String s = System.getProperty("line.separator");
+ String line = reader.readLine();
+
+ while (line != null)
+ {
+ error.append(line);
+ line = reader.readLine();
+
+ if (line != null)
+ {
+ error.append(s);
+ }
+ }
+
+ if (logger.isWarnEnabled())
+ {
+ logger.warn(error.toString());
+ }
+ }
+ finally
+ {
+ IOUtil.close(reader);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param is
+ *
+ * @throws IOException
+ */
+ private void processProcessInputStream(InputStream is) throws IOException
+ {
+ parseHeaders(is);
+
+ ServletOutputStream servletOS = null;
+
+ try
+ {
+ servletOS = response.getOutputStream();
+ IOUtil.copy(is, servletOS, bufferSize);
+ }
+ finally
+ {
+ IOUtil.close(servletOS);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param process
+ */
+ private void processServletInput(Process process)
+ {
+ OutputStream processOS = null;
+ ServletInputStream servletIS = null;
+
+ try
+ {
+ processOS = process.getOutputStream();
+ servletIS = request.getInputStream();
+ IOUtil.copy(servletIS, processOS, bufferSize);
+ }
+ catch (IOException ex)
+ {
+ logger.error(
+ "could not read from ServletInputStream and write to ProcessOutputStream",
+ ex);
+ }
+ finally
+ {
+ IOUtil.close(processOS);
+ IOUtil.close(servletIS);
+ }
+ }
+
+ /**
+ * Method description
+ *
+ *
+ * @param process
+ *
+ */
+ private void waitForFinish(Process process)
+ {
+ try
+ {
+ int exitCode = process.waitFor();
+
+ if (exitCode != 0)
+ {
+ logger.warn("process ends with exit code {}", exitCode);
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ logger.error("process interrupted", ex);
+ }
+ }
+
+ //~--- get methods ----------------------------------------------------------
+
+ /**
+ * Method description
+ *
+ *
+ * @param is
+ *
+ * @return
+ *
+ * @throws IOException
+ */
+ private String getTextLineFromStream(InputStream is) throws IOException
+ {
+ StringBuilder buffer = new StringBuilder();
+ int b;
+
+ while ((b = is.read()) != -1 && (b != (int) '\n'))
+ {
+ buffer.append((char) b);
+ }
+
+ return buffer.toString().trim();
+ }
+
+ //~--- fields ---------------------------------------------------------------
+
+ /** Field description */
+ private ScmConfiguration configuration;
+
+ /** Field description */
+ private ServletContext context;
+
+ /** Field description */
+ private HttpServletRequest request;
+
+ /** Field description */
+ private HttpServletResponse response;
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java
new file mode 100644
index 0000000000..eaa89224e2
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/web/cgi/DefaultCGIExecutorFactory.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+
+
+package sonia.scm.web.cgi;
+
+//~--- non-JDK imports --------------------------------------------------------
+
+import sonia.scm.config.ScmConfiguration;
+
+//~--- JDK imports ------------------------------------------------------------
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author Sebastian Sdorra
+ */
+public class DefaultCGIExecutorFactory implements CGIExecutorFactory
+{
+
+ /**
+ * Method description
+ *
+ *
+ * @param configuration
+ * @param context
+ * @param request
+ * @param response
+ *
+ * @return
+ */
+ @Override
+ public CGIExecutor createExecutor(ScmConfiguration configuration,
+ ServletContext context,
+ HttpServletRequest request,
+ HttpServletResponse response)
+ {
+ return new DefaultCGIExecutor(configuration, context, request, response);
+ }
+}