Skip to content
Snippets Groups Projects
Commit fd7f40f7 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

BUG: remove tmp files after termination

parent 1671c115
No related branches found
No related tags found
No related merge requests found
......@@ -22,8 +22,8 @@
*/
package caosdb.server;
public class CaosDBException extends Exception {
/** */
public class CaosDBException extends RuntimeException {
private static final long serialVersionUID = 5317733089121727021L;
public CaosDBException(final String string) {
......
......@@ -256,6 +256,10 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
this.xslScript = s;
}
protected JdomRepresentation ok(Element root) {
return ok(new Document(root));
}
protected JdomRepresentation ok(final Document doc) {
return new JdomRepresentation(doc, MediaType.TEXT_XML, " ", getReference(), getXSLScript());
}
......@@ -339,6 +343,14 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
return this.flags;
}
protected Element generateRootElement(Element... elements) {
Element root = generateRootElement();
for (Element e : elements) {
root.addContent(e);
}
return root;
}
public static class XMLParser {
private final LinkedList<SAXBuilder> pool = new LinkedList<SAXBuilder>();
private final int max = 25;
......
......@@ -22,28 +22,29 @@
*/
package caosdb.server.resource;
import caosdb.server.CaosDBException;
import caosdb.server.FileSystem;
import caosdb.server.accessControl.Principal;
import caosdb.server.accessControl.SessionToken;
import caosdb.server.entity.FileProperties;
import caosdb.server.entity.Message;
import caosdb.server.scripting.ScriptingUtils;
import caosdb.server.scripting.CallerSerializer;
import caosdb.server.scripting.ServerSideScriptingCaller;
import caosdb.server.utils.Serializer;
import caosdb.server.utils.ServerMessages;
import caosdb.server.utils.Utils;
import com.ibm.icu.text.Collator;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.restlet.data.CharacterSet;
import org.restlet.data.Form;
......@@ -57,94 +58,55 @@ import org.restlet.representation.Representation;
public class ScriptingResource extends AbstractCaosDBServerResource {
private ServerSideScriptingCaller caller;
private Collection<FileProperties> deleteFiles = new LinkedList<>();
@Override
public Logger getLogger() {
return Logger.getLogger(this.getClass().getName());
}
/*
* TODO move to pyinttest
*/
public void setupTestCase(String queryValue) throws IOException {
switch (queryValue) {
case "call_not_executable":
File file1 = new ScriptingUtils().getScriptFile("not_executable");
file1.getParentFile().mkdirs();
file1.createNewFile();
break;
case "call_ok":
File file2 = new ScriptingUtils().getScriptFile("ok");
file2.getParentFile().mkdirs();
file2.createNewFile();
FileUtils.write(file2, "echo ok");
file2.setExecutable(true);
break;
case "call_err":
File file3 = new ScriptingUtils().getScriptFile("err");
file3.getParentFile().mkdirs();
file3.createNewFile();
FileUtils.write(file3, ">&2 echo \"err\"; exit 1");
file3.setExecutable(true);
break;
default:
break;
}
}
/*
* TODO move to serialization class
*/
public Element generateResponse(
Integer code, String[] commandLine, String stdOut, String stdErr) {
Element callElem = new Element("call");
callElem.setText(String.join(" ", commandLine));
Element stdErrElem = new Element("stderr");
stdErrElem.addContent(stdErr);
Element stdOutElem = new Element("stdout");
stdOutElem.addContent(stdOut);
public Element generateRootElement(ServerSideScriptingCaller caller) {
Serializer<ServerSideScriptingCaller, Element> xmlSerializer = new CallerSerializer();
Element callerElement = xmlSerializer.serialize(caller);
Element scriptElem = new Element("script");
scriptElem.setAttribute("code", code.toString());
scriptElem.addContent(callElem);
scriptElem.addContent(stdOutElem);
scriptElem.addContent(stdErrElem);
Element root = generateRootElement();
root.addContent(scriptElem);
return root;
return generateRootElement(callerElement);
}
@Override
protected Representation httpPostInChildClass(Representation entity) throws Exception {
MediaType mediaType = entity.getMediaType();
int code;
try {
if (mediaType.equals(MediaType.MULTIPART_FORM_DATA, true)) {
code = handleMultiparts(entity);
handleMultiparts(entity);
} else if (mediaType.equals(MediaType.APPLICATION_WWW_FORM)) {
code = handleForm(new Form(entity));
handleForm(new Form(entity));
} else {
getResponse().setStatus(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE);
return null;
}
} catch (Message m) {
return error(m, Status.valueOf(m.getCode()));
} finally {
deleteTmpFiles();
}
return ok(generateRootElement(this.caller));
}
private void deleteTmpFiles() {
for (FileProperties p : deleteFiles) {
try {
p.deleteFile();
} catch (Exception t) {
if (getLogger().isLoggable(Level.WARNING)) {
getLogger().warning("Could not delete tmp file: " + t.toString());
}
}
}
return ok(
new Document(
generateResponse(
code,
this.caller.getCommandLine(),
this.caller.getStdOut(),
this.caller.getStdErr())));
}
public int handleMultiparts(Representation entity)
throws FileUploadException, IOException, NoSuchAlgorithmException, CaosDBException, Message {
throws FileUploadException, IOException, NoSuchAlgorithmException, Message {
final DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1000240);
final RestletFileUpload upload = new RestletFileUpload(factory);
......@@ -158,11 +120,15 @@ public class ScriptingResource extends AbstractCaosDBServerResource {
if (item.isFormField()) {
// put plain text form field into the form
CharacterSet characterSet = ContentType.readCharacterSet(item.getContentType());
String value = Utils.InputStream2String(item.openStream(), (characterSet!=null?characterSet.toString():CharacterSet.UTF_8.toString()));
String value =
Utils.InputStream2String(
item.openStream(),
(characterSet != null ? characterSet.toString() : CharacterSet.UTF_8.toString()));
form.add(new Parameter(item.getFieldName(), value));
} else {
// -> this is a file, store in tmp dir
final FileProperties file = FileSystem.upload(item, this.getSRID());
deleteTmpFileAfterTermination(file);
file.setPath(item.getName());
file.setTmpIdentifyer(item.getFieldName());
files.add(file);
......@@ -175,11 +141,15 @@ public class ScriptingResource extends AbstractCaosDBServerResource {
return callScript(form, files);
}
private void deleteTmpFileAfterTermination(FileProperties file) {
deleteFiles.add(file);
}
public int handleForm(Form form) throws Message {
return callScript(form, null);
}
public List<String> form2CommandLine(Form form) {
public List<String> form2CommandLine(Form form) throws Message {
ArrayList<String> commandLine = new ArrayList<>(form.size());
ArrayList<Parameter> positionalArgs = new ArrayList<>(form.size() - 1);
......@@ -203,7 +173,7 @@ public class ScriptingResource extends AbstractCaosDBServerResource {
if (commandLine.get(0).length() == 0) {
// first item still empty
throw new RuntimeException("Missing form field `call`.");
throw ServerMessages.SERVER_SIDE_SCRIPT_MISSING_CALL;
}
return commandLine;
}
......
package caosdb.server.scripting;
import caosdb.server.CaosDBException;
import caosdb.server.utils.Serializer;
import java.io.IOException;
import org.jdom2.Element;
public class CallerSerializer implements Serializer<ServerSideScriptingCaller, Element> {
@Override
public Element serialize(ServerSideScriptingCaller caller) {
Element command = new Element("call");
command.setText(String.join(" ", caller.getCommandLine()));
Element stdout = new Element("stdout");
try {
stdout.addContent(caller.getStdOut());
} catch (IOException e) {
throw new CaosDBException(e);
}
Element stderr = new Element("stderr");
try {
stderr.addContent(caller.getStdErr());
} catch (IOException e) {
throw new CaosDBException(e);
}
Element script = new Element("script");
script.setAttribute("code", caller.getCode().toString());
script.addContent(command);
script.addContent(stdout);
script.addContent(stderr);
return script;
}
}
......@@ -37,6 +37,7 @@ import org.apache.commons.io.FileUtils;
public class ServerSideScriptingCaller {
public static final String UPLOAD_FILES_DIR = ".upload_files";
public static final Integer STARTED = -1;
private final String[] commandLine;
private final int timeoutMs;
private ScriptingUtils utils;
......@@ -47,6 +48,11 @@ public class ServerSideScriptingCaller {
private File stdErrFile;
private String stdErr = null;
private String stdOut;
private Integer code = null;
public Integer getCode() {
return code;
}
File getUploadFilesDir() {
return getTmpWorkingDir().toPath().resolve(UPLOAD_FILES_DIR).toFile();
......@@ -188,9 +194,11 @@ public class ServerSideScriptingCaller {
pb.redirectError(Redirect.to(getStdErrFile()));
pb.directory(getTmpWorkingDir());
code = STARTED;
final TimeoutProcess process = new TimeoutProcess(pb.start(), getTimeoutMs());
return process.waitFor();
code = process.waitFor();
return code;
}
public File getStdOutFile() {
......
package caosdb.server.utils;
public interface Serializer<T, S> {
public S serialize(T object);
}
......@@ -71,7 +71,7 @@ public class TestScriptingResource {
}
@Test
public void testForm2invocation() {
public void testForm2invocation() throws Message {
Form form =
new Form(
"-Ooption=OPTION&call=CA%20LL&-Ooption2=OPTION2&-p=POS1&-p4=POS3&-p2=POS2&IGNORED");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment