Implement mercurial cgi protocol as extension (#1458)

* Handle mercurial cgi protocol with an hg extension
* Refactor CGI executor to allow command arguments
* Unify python scripts and hg extensions
* Implement new auto configuration
* Use HKEY_LOCAL_MACHINE instead of
  HKEY_CURRENT_USER registry keys to find mercurial
  installations on windows
This commit is contained in:
Sebastian Sdorra
2020-12-17 10:06:55 +01:00
committed by René Pfeuffer
parent 99d389b2af
commit b61d817c9c
65 changed files with 1164 additions and 4327 deletions

View File

@@ -21,12 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.web.cgi;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.io.ByteStreams;
@@ -48,7 +49,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
@@ -110,18 +113,8 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
*
* @param cmd
*
* @throws IOException
*/
@Override
public void execute(String cmd) throws IOException
public void execute(String cmd)
{
File command = new File(cmd);
EnvList env = new EnvList(environment);
@@ -150,21 +143,16 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
env.set(ENV_PATH_TRANSLATED, pathTranslated);
String execCmd = path;
if ((execCmd.charAt(0) != '"') && (execCmd.indexOf(' ') >= 0))
{
execCmd = "\"".concat(execCmd).concat("\"");
}
if (interpreter != null)
{
execCmd = interpreter.concat(" ").concat(execCmd);
List<String> execCmd = new ArrayList<>();
if (interpreter != null) {
execCmd.add(interpreter);
}
execCmd.add(command.getAbsolutePath());
execCmd.addAll(getArgs());
if (logger.isDebugEnabled())
{
logger.debug("execute cgi: {}", execCmd);
logger.debug("execute cgi: {}", Joiner.on(' ').join(execCmd));
if (logger.isTraceEnabled())
{
@@ -173,10 +161,11 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
}
Process p = null;
try
{
p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), workDirectory);
try {
ProcessBuilder builder = new ProcessBuilder(execCmd);
builder.directory(workDirectory);
builder.environment().putAll(env.asMap());
p = builder.start();
execute(p);
}
catch (IOException ex)
@@ -329,15 +318,14 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
env.set(ENV_SERVER_SOFTWARE,
SERVER_SOFTWARE_PREFIX.concat(SCMContext.getContext().getVersion()));
Enumeration enm = request.getHeaderNames();
Enumeration<String> enm = request.getHeaderNames();
while (enm.hasMoreElements())
{
String name = (String) enm.nextElement();
String name = enm.nextElement();
String value = request.getHeader(name);
env.set(ENV_HTTP_HEADER_PREFIX + name.toUpperCase().replace('-', '_'),
value);
env.set(ENV_HTTP_HEADER_PREFIX + name.toUpperCase().replace('-', '_'), value);
}
// these extra ones were from printenv on www.dev.nomura.co.uk
@@ -394,6 +382,7 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
*
* @throws IOException
*/
@SuppressWarnings("UnstableApiUsage")
private void execute(Process process) throws IOException
{
InputStream processIS = null;
@@ -418,61 +407,26 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
}
}
/**
* Method description
*
*
* @param is
*
*
* @throws IOException
*/
private void parseHeaders(InputStream is) throws IOException
{
private void parseHeaders(InputStream is) throws IOException {
String line = null;
while ((line = getTextLineFromStream(is)).length() > 0)
{
if (logger.isTraceEnabled())
{
while ((line = getTextLineFromStream(is)).length() > 0) {
if (logger.isTraceEnabled()) {
logger.trace(" ".concat(line));
}
if (!line.startsWith(RESPONSE_HEADER_HTTP_PREFIX))
{
if (!line.startsWith(RESPONSE_HEADER_HTTP_PREFIX)) {
int k = line.indexOf(':');
if (k > 0)
{
if (k > 0) {
String key = line.substring(0, k).trim();
String value = line.substring(k + 1).trim();
if (RESPONSE_HEADER_LOCATION.equalsIgnoreCase(key))
{
if (RESPONSE_HEADER_LOCATION.equalsIgnoreCase(key)) {
response.sendRedirect(response.encodeRedirectURL(value));
}
else if (RESPONSE_HEADER_STATUS.equalsIgnoreCase(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
{
} else if (RESPONSE_HEADER_STATUS.equalsIgnoreCase(key)) {
handleStatus(value);
} else {
// add remaining header items to our response header
response.addHeader(key, value);
}
@@ -481,6 +435,19 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
}
}
private void handleStatus(String value) throws IOException {
String[] token = value.split(" ");
int status = Integer.parseInt(token[0]);
logger.debug("CGI returned with status {}", status);
if (status < 304) {
response.setStatus(status);
} else {
response.sendError(status);
}
}
/**
* Method description
*
@@ -513,26 +480,21 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
*/
private void processErrorStreamAsync(final Process process)
{
executor.execute(new Runnable()
{
@Override
public void run()
{
InputStream errorStream = null;
executor.execute(() -> {
InputStream errorStream = null;
try
{
errorStream = process.getErrorStream();
processErrorStream(errorStream);
}
catch (IOException ex)
{
logger.error("could not read errorstream", ex);
}
finally
{
IOUtil.close(errorStream);
}
try
{
errorStream = process.getErrorStream();
processErrorStream(errorStream);
}
catch (IOException ex)
{
logger.error("could not read errorstream", ex);
}
finally
{
IOUtil.close(errorStream);
}
});
}
@@ -615,6 +577,7 @@ public class DefaultCGIExecutor extends AbstractCGIExecutor
catch (InterruptedException ex)
{
getExceptionHandler().handleException(request, response, ex);
Thread.currentThread().interrupt();
}
}