All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.rivulet.internal.server.EmbeddedServer Maven / Gradle / Ivy

The newest version!
package io.rivulet.internal.server;

import edu.columbia.cs.psl.phosphor.BasicSourceSinkManager;
import edu.columbia.cs.psl.phosphor.Configuration;
import edu.columbia.cs.psl.phosphor.Instrumenter;
import io.rivulet.fuzz.RerunProgress;
import io.rivulet.internal.RivuletAutoTaintWrapper;
import io.rivulet.internal.fuzz.generator.RerunGeneratorWrapper;
import io.rivulet.internal.rerun.TestRerunConfiguration;
import org.apache.http.Consts;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public abstract class EmbeddedServer {

	// Path of the base directory used by Tomcat
	protected static final String tomcatBaseDir = System.getProperty("tomcat.base.directory", "tomcat");
	// Path of the directory to which web application files are extracted
	protected static final String webAppsBaseDir = System.getProperty("webapps.base.directory", "webapps");
	// Path of the directory containing war files for the web applications
	protected static final String webAppsWarDir = ".." + File.separator + "experiments" + File.separator + "apache-tomcat-8.0.47" + File.separator + "webapps";
	// Set of names of the web applications already added to tomcat
	protected static final HashSet addedWebApps = new HashSet<>();
	// The last generator that was used to provide a set of sink methods. A null value indicates that Instrumenter.sinksFile
	// was used to provide sinks, i.e. the same sinks that were used for the original run were used.
	private static RerunGeneratorWrapper sinksProvider = null;
	protected int tomcatPort;
	protected int socketPort;
	private Thread clientCommunicationHandlingThread;
	private ServerSocket receiverSocket;
	private ServerTaintTrackingTestListener taintTrackingTestListener;
	private RerunProgress rerunProgress = new RerunProgress();

	protected EmbeddedServer(String[] args) {
//		this.infoFile = args[0]; //first arg is file to write out port numbers to
		this.tomcatPort = Integer.valueOf(args[0]);
		this.socketPort = Integer.valueOf(args[1]);
	}
	protected void doneAddingWebApps() throws Exception{

	}

	public static void main(String[] args) {
		EmbeddedServer server = new TomcatEmbeddedServer(args);//JettyEmbeddedServer(args);
		server.start();
		if (args.length > 2) {
			try {
				server.addWebApp(args[2], args[3]);
				server.doneAddingWebApps();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/* Returns a newly created file handler with the specified logging level that logs to a file in the base tomcat directory. */
	private static Handler createFileHandler() throws IOException {
		// Ensure that the base directory exists
		File baseDirFile = new File(tomcatBaseDir);
		if (!baseDirFile.isDirectory() && !baseDirFile.mkdirs()) {
			System.err.println("Failed to make base directory for embedded tomcat.");
		}
		Handler fileHandler = new FileHandler(tomcatBaseDir + File.separator + "catalina.out", true);
		fileHandler.setFormatter(new SimpleFormatter());
		fileHandler.setLevel(Level.INFO);
		fileHandler.setEncoding("UTF-8");
		return fileHandler;
	}

	/* Removes any existing handlers for the specified logger and adds the specified handler. */
	protected static void replaceRootLoggerHandlers() throws IOException {
		Logger rootLogger = LogManager.getLogManager().getLogger("");
		rootLogger.setUseParentHandlers(false);
		// Change the level of any existing handlers to OFF
		for (Handler h : rootLogger.getHandlers()) {
			h.setLevel(Level.OFF);
		}
		// Add a file handler for INFO level logging
		rootLogger.addHandler(createFileHandler());
	}

	/* If the directory for the web-app with the specified name does not exists creates it by unzipping the war for the
	 * web-app. */
	protected static void unzipWar(String warFile, String name) throws IOException {
		File dir = new File(webAppsBaseDir, name);
		if (!dir.isDirectory()) {
			// Unzip war into the directory only if it does not already exists
			File webAppWar = new File(warFile);
			if (!webAppWar.isFile()) {
				throw new RuntimeException("Could not find war file for: " + name);
			}
			try (ZipFile zipFile = new ZipFile(webAppWar)) {
				Enumeration entries = zipFile.entries();
				while (entries.hasMoreElements()) {
					ZipEntry entry = entries.nextElement();
					File entryDestination = new File(dir, entry.getName());
					if (entry.isDirectory()) {
						if (!entryDestination.isDirectory() && !entryDestination.mkdirs()) {
							throw new RuntimeException("Failed to make directory for: " + entryDestination);
						}
						//JON: DO NOT DO THIS GENERALLY, IT WILL KILL APPS THAT DEPEND ON NO FILE HERE
						// Add velocity.properties file
//						File velocityPropFile = new File(entryDestination, "velocity.properties");
//						try {
//							org.apache.commons.io.FileUtils.writeStringToFile(velocityPropFile,
//									"runtime.log.logsystem.class=org.apache.velocity.runtime.log.NullLogChute", Consts.UTF_8, false);
//						} catch (Exception e) {
//							//
//						}
					} else {
						if (!entryDestination.getParentFile().isDirectory() && !entryDestination.getParentFile().mkdirs()) {
							throw new RuntimeException("Failed to make directory for: " + entryDestination.getParentFile());
						}
//						if (entry.getName().endsWith("log4j.properties")) {
//							// Write different logging properties
//							writeLog4JProperties(entryDestination);
//						} else {
						InputStream in = zipFile.getInputStream(entry);
						OutputStream out = new FileOutputStream(entryDestination);
						IOUtils.copy(in, out);
						IOUtils.closeQuietly(in);
						out.close();
//						}
					}
				}
			}
		}
	}

	/* Writes log4j properties to disable logging to the specified file. */
	private static void writeLog4JProperties(File file) throws IOException {
		String content =
				"log4j.rootLogger=OFF, stdout\n" +
						"log4j.appender.stdout=org.apache.log4j.ConsoleAppender\n" +
						"log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout\n";
		org.apache.commons.io.FileUtils.writeStringToFile(file,
				content, Consts.UTF_8, false);
	}

	public abstract void addWebApp(String warFilePath, String shortName) throws IOException;

	public abstract void addWebApp(String name) throws Exception;

	protected abstract void startWebServer();

	protected abstract int getPort();

	public void start() {
		try {
			startWebServer();
			receiverSocket = new ServerSocket(socketPort);
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.clientCommunicationHandlingThread = new Thread(() -> {
			try {
//				FileWriter portWriter = new FileWriter(infoFile);
//				portWriter.write(receiverSocket.getLocalPort() + "\n");
//				portWriter.write(tomcat.getConnector().getLocalPort() + "\n");
				System.out.println("Control port: " + receiverSocket.getLocalPort());
				System.out.println("Tomcat port: " + getPort());
//				portWriter.close();
				while (true) {
					Socket channel = receiverSocket.accept();
					Thread clientThread = new Thread(() -> {
						try {
							try {
								DataInputStream is = new DataInputStream(new BufferedInputStream(channel.getInputStream()));
								DataOutputStream os = new DataOutputStream(new BufferedOutputStream(channel.getOutputStream()));
								PrintWriter outputPrinter = new PrintWriter(channel.getOutputStream());
								while (true) {
									EmbeddedMessageImpl message = EmbeddedMessageImpl.fromInput(is);
									message.apply(this, os);
								}
							} catch (EOFException ex) {
								return;
							} catch (ClassNotFoundException e) {
								e.printStackTrace();
							} finally {
								channel.close();
							}
						} catch (IOException ex) {
							ex.printStackTrace();
						}
					});
					clientThread.start();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		});
		this.clientCommunicationHandlingThread.setDaemon(true);
		this.clientCommunicationHandlingThread.start();
	}

	public ServerTaintTrackingTestListener getTaintTrackingTestListener() {
		return taintTrackingTestListener;
	}

	public void initListener(String rerunConfigsPath, String violationReportsPath, String criticalReproductionPath) {
		this.taintTrackingTestListener = new ServerTaintTrackingTestListener(this, rerunConfigsPath, violationReportsPath, criticalReproductionPath, new RerunProgress());
	}

	public void setRerunConfigAndResetAutoTaint(TestRerunConfiguration config) {
		RivuletAutoTaintWrapper.setCurrentRerunConfig(config);
		// Swap the taintSourceWrapper class and the sink methods
		if (config.getAutoTainterClass() != null) {
			try {
				Configuration.autoTainter = config.getAutoTainterClass().newInstance();
				if (Configuration.autoTainter instanceof RerunGeneratorWrapper) {
					RerunGeneratorWrapper generator = (RerunGeneratorWrapper) Configuration.autoTainter;
					// Check if the generator that supplied the current set of sinks is different
					if (!generator.equals(sinksProvider)) {
						if (generator.getTargetedBaseSinks() != null) {
							// Generator has custom sink set
							sinksProvider = generator;
							BasicSourceSinkManager.replaceAutoTaintMethods(generator.getTargetedBaseSinks(), BasicSourceSinkManager.AutoTaint.SINK);
						} else if (sinksProvider != null) {
							// Use default sink set
							sinksProvider = null;
							BasicSourceSinkManager.replaceAutoTaintMethods(Instrumenter.sinksFile, BasicSourceSinkManager.AutoTaint.SINK);
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				Configuration.autoTainter = new RivuletAutoTaintWrapper();
				// Check if the generator that supplied the current set of sinks is different
				if (sinksProvider != null) {
					sinksProvider = null;
					BasicSourceSinkManager.replaceAutoTaintMethods(Instrumenter.sinksFile, BasicSourceSinkManager.AutoTaint.SINK);
				}
			}
		} else {
			Configuration.autoTainter = new RivuletAutoTaintWrapper();
			// Check if the generator that supplied the current set of sinks is different
			if (sinksProvider != null) {
				sinksProvider = null;
				BasicSourceSinkManager.replaceAutoTaintMethods(Instrumenter.sinksFile, BasicSourceSinkManager.AutoTaint.SINK);
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy