/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.tomcat.util.net.ocsp;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.apache.tomcat.util.net.TesterSupport;
/*
* The OpenSSL ocsp tool is great, but it does generate a lot of output. That output needs to be swallowed, else the
* process will freeze when the output buffers (stdout and stderr) are full.
*
* There is a command line option to redirect stdout (which could be redirected to /dev/null), but there is no option to
* redirect stderr. Therefore, this class uses a couple of dedicated threads to read stdout and stderr. By default, the
* output is ignored, but it can be dumped to Java's stdout/stderr if required for debugging purposes.
*/
public class TesterOcspResponder {
private static List<String> ocspArgs = Arrays.asList("ocsp", "-port", "8888", "-text", "-index",
TesterSupport.DB_INDEX, "-CA", TesterSupport.CA_CERT_PEM, "-rkey", TesterSupport.OCSP_RESPONDER_RSA_KEY,
"-rsigner", TesterSupport.OCSP_RESPONDER_RSA_CERT, "-nmin", "60");
private Process p;
public void start() throws IOException {
if (p != null) {
throw new IllegalStateException("Already started");
}
String openSSLPath = System.getProperty("tomcat.test.openssl.path");
String openSSLLibPath = null;
if (openSSLPath == null || openSSLPath.length() == 0) {
openSSLPath = "openssl";
} else {
// Explicit OpenSSL path may also need explicit lib path
// (e.g. Gump needs this)
openSSLLibPath = openSSLPath.substring(0, openSSLPath.lastIndexOf('/'));
openSSLLibPath = openSSLLibPath + "/../:" + openSSLLibPath + "/../lib:" + openSSLLibPath + "/../lib64";
}
List<String> cmd = new ArrayList<>();
cmd.add(openSSLPath);
cmd.addAll(ocspArgs);
ProcessBuilder pb = new ProcessBuilder(cmd.toArray(new String[0]));
if (openSSLLibPath != null) {
Map<String,String> env = pb.environment();
String libraryPath = env.get("LD_LIBRARY_PATH");
if (libraryPath == null) {
libraryPath = openSSLLibPath;
} else {
libraryPath = libraryPath + ":" + openSSLLibPath;
}
env.put("LD_LIBRARY_PATH", libraryPath);
}
p = pb.start();
redirect(p.inputReader(), System.out, true);
redirect(p.errorReader(), System.err, true);
Assert.assertTrue(p.isAlive());
}
public void stop() {
if (p == null) {
throw new IllegalStateException("Not started");
}
p.destroy();
try {
if (!p.waitFor(30, TimeUnit.SECONDS)) {
throw new IllegalStateException("Failed to stop");
}
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupted while waiting to stop", e);
}
}
private void redirect(final Reader r, final PrintStream os, final boolean swallow) {
/*
* InputStream will close when process ends. Thread will exit once stream closes.
*/
new Thread( () -> {
char[] cbuf = new char[1024];
try {
int read;
while ((read = r.read(cbuf)) > 0) {
if (!swallow) {
os.print(new String(cbuf, 0, read));
}
}
} catch (IOException ignore) {
// Ignore
}
}).start();
}
}