Skip to content
Permalink
Browse files

In service of issue #176, support posting multipart/form-data to pipe…

…lines. Also distribute the restlet jars.
  • Loading branch information
ndw committed Sep 14, 2014
1 parent a9e1855 commit 93f2f2c790c62a589362743ac28f76f78c5e6a2f
@@ -539,6 +539,8 @@ java -Xmx1024m -jar %INSTALL_PATH/calabash.jar "$@"
<copy todir="${install.dir}/lib">
<fileset file="lib/commons*.jar"/>
<fileset file="lib/http*.jar"/>
<fileset file="lib/org.restlet*.jar"/>
<fileset file="lib/servlet-api.jar"/>
<fileset file="lib/log4j*.jar"/>
<fileset file="lib/slf4j*.jar"/>
<fileset file="lib/jcl-over-slf4j*.jar"/>
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN -45.5 KB (94%) lib/org.restlet.jar
Binary file not shown.
BIN +238 KB lib/servlet-api.jar
Binary file not shown.
@@ -1,10 +1,14 @@
package com.xmlcalabash.piperack;

import com.xmlcalabash.core.XProcConfiguration;
import com.xmlcalabash.core.XProcConstants;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.ReadableData;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.io.WritableDocument;
import com.xmlcalabash.model.DeclareStep;
import com.xmlcalabash.model.RuntimeValue;
import com.xmlcalabash.model.Serialization;
import com.xmlcalabash.runtime.XPipeline;
import com.xmlcalabash.util.TreeWriter;
@@ -16,25 +20,25 @@
import net.sf.saxon.s9api.XsltCompiler;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.ServerInfo;
import org.restlet.data.Status;
import org.restlet.ext.fileupload.RestletFileUpload;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.representation.Variant;
import org.restlet.resource.ServerResource;
import org.xml.sax.InputSource;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Vector;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -335,4 +339,120 @@ protected Representation getOutput(PipelineConfiguration pipeconfig, String port
throw new XProcException(e);
}
}

protected Representation processMultipartForm(PipelineConfiguration pipeconfig, Representation entity, Variant variant) {
XPipeline xpipeline = pipeconfig.pipeline;
XProcRuntime runtime = pipeconfig.runtime;

if (pipeconfig.ran) {
pipeconfig.reset();
xpipeline.reset();
}

String message = "";

HashMap<String,String> nameValuePairs = new HashMap<String,String> ();
HashMap<String,String> nsBindings = new HashMap<String,String> ();

DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(100240);

RestletFileUpload upload = new RestletFileUpload(factory);
List<FileItem> items;
try {
items = upload.parseRequest(getRequest());

File file = null;
String filename = null;

for (final Iterator<FileItem> it = items.iterator(); it.hasNext(); ) {
FileItem fi = it.next();
String fieldName = fi.getFieldName();
String name = fi.getName();

if (name == null) {
Matcher matcher = xmlnsRE.matcher(fieldName);
if (matcher.matches()) {
nsBindings.put(matcher.group(1), new String(fi.get(), "utf-8"));
} else {
nameValuePairs.put(fieldName, new String(fi.get(), "utf-8"));
}
} else {
String port = fieldName;

if (pipeconfig.documentCount(port) == 0) {
xpipeline.clearInputs(port);
}
pipeconfig.writeTo(port);

try {
XdmNode doc = null;
MediaType m = new MediaType(fi.getContentType());

if (isXml(m)) {
doc = runtime.parse(new InputSource(fi.getInputStream()));
} else {
ReadablePipe pipe = null;
pipe = new ReadableData(runtime, XProcConstants.c_data, fi.getInputStream(), fi.getContentType());
doc = pipe.read();
}
xpipeline.writeTo(port, doc);
} catch (Exception e) {
throw new XProcException(e);
}

message += "Posted input to port '" + port + "'\n";
}
}


for (String fieldName : nameValuePairs.keySet()) {
QName qname = qnameFromForm(fieldName, nsBindings);
RuntimeValue value = new RuntimeValue(nameValuePairs.get(fieldName));
DeclareStep pipeline = xpipeline.getDeclareStep();

boolean option = false;
for (QName oname : pipeline.getOptions()) {
option = option || oname.equals(qname);
}

// Note: We explicitly set option to true again so that the behavior of
// multipart forms is consistent with the behavior of non-form data.
// Maybe I should support posting parameters like this in both cases.

option = true;

if (option) {
xpipeline.passOption(qname, value);
pipeconfig.setGVOption(qname);
message += "Option " + qname.getClarkName() + "=" + value.getString() + "\n";
} else {
String port = null;
if (port == null) {
// Figure out the default parameter port
for (String iport : xpipeline.getInputs()) {
com.xmlcalabash.model.Input input = pipeline.getInput(iport);
if (input.getParameterInput() && input.getPrimary()) {
port = iport;
}
}
}

if (port == null) {
throw new XProcException("No primary parameter input port.");
}

xpipeline.setParameter(port, qname, value);
pipeconfig.setParameter(qname, value.getString());
message += "Parameter " + qname.getClarkName() + "=" + value.getString() + "\n";
}
}

return okResponse(message, variant.getMediaType(), Status.SUCCESS_OK);
} catch (XProcException e) {
throw e;
} catch (Exception e) {
throw new XProcException(e);
}
}
}
@@ -4,37 +4,22 @@
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.ReadableData;
import com.xmlcalabash.io.ReadableDocument;
import com.xmlcalabash.io.ReadableInline;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.model.DeclareStep;
import com.xmlcalabash.model.RuntimeValue;
import com.xmlcalabash.runtime.XPipeline;
import com.xmlcalabash.util.TreeWriter;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
import org.restlet.Request;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.engine.header.Header;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.representation.Variant;
import org.restlet.util.Series;
import org.xml.sax.InputSource;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.util.HashMap;
import java.util.Random;
import java.util.Vector;
import java.util.*;

/**
* Ths file is part of XMLCalabash.
@@ -180,41 +165,44 @@ protected Representation post(Representation entity, Variant variant) {
XPipeline xpipeline = pipeconfig.pipeline;
XProcRuntime runtime = pipeconfig.runtime;

if (pipeconfig.definput == null) {
return badRequest(Status.CLIENT_ERROR_BAD_REQUEST, "No primary input port", variant.getMediaType());
}

if (pipeconfig.ran) {
pipeconfig.reset();
xpipeline.reset();
}

if (pipeconfig.documentCount(pipeconfig.definput) == 0) {
xpipeline.clearInputs(pipeconfig.definput);
}
pipeconfig.writeTo(pipeconfig.definput);

try {
XdmNode doc = null;

if (isXml(entity.getMediaType())) {
doc = runtime.parse(new InputSource(entity.getStream()));
if (MediaType.MULTIPART_FORM_DATA.equals(entity.getMediaType(), true)) {
processMultipartForm(pipeconfig, entity, variant);
} else {
ReadablePipe pipe = null;
pipe = new ReadableData(runtime, XProcConstants.c_data, entity.getStream(), entity.getMediaType().toString());
doc = pipe.read();
}
if (pipeconfig.definput == null) {
return badRequest(Status.CLIENT_ERROR_BAD_REQUEST, "No primary input port", variant.getMediaType());
}
if (pipeconfig.documentCount(pipeconfig.definput) == 0) {
xpipeline.clearInputs(pipeconfig.definput);
}
pipeconfig.writeTo(pipeconfig.definput);

xpipeline.writeTo(pipeconfig.definput, doc);
} catch (Exception e) {
throw new XProcException(e);
}
XdmNode doc = null;

if (isXml(entity.getMediaType())) {
doc = runtime.parse(new InputSource(entity.getStream()));
} else {
ReadablePipe pipe = null;
pipe = new ReadableData(runtime, XProcConstants.c_data, entity.getStream(), entity.getMediaType().toString());
doc = pipe.read();
}

HashMap<QName,String> options = convertForm(getQuery());
xpipeline.writeTo(pipeconfig.definput, doc);

for (QName name : options.keySet()) {
RuntimeValue value = new RuntimeValue(options.get(name), null, null);
xpipeline.passOption(name, value);
HashMap<QName, String> options = convertForm(getQuery());

for (QName name : options.keySet()) {
RuntimeValue value = new RuntimeValue(options.get(name), null, null);
xpipeline.passOption(name, value);
}
}
} catch (Exception e) {
return badRequest(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage(), variant.getMediaType());
}

return runPipeline(id);
@@ -1,8 +1,10 @@
package com.xmlcalabash.piperack;

import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.model.RuntimeValue;
import com.xmlcalabash.runtime.XPipeline;
import net.sf.saxon.s9api.QName;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.Variant;
@@ -21,15 +23,26 @@ protected Representation post(Representation entity, Variant variant) {
return badRequest(Status.CLIENT_ERROR_NOT_FOUND, "no pipeline: " + pipelineUri(id), variant.getMediaType());
}

HashMap<QName,String> options = convertForm(getQuery());

PipelineConfiguration pipeconfig = getPipelines().get(id);
XPipeline xpipeline = pipeconfig.pipeline;

for (QName name : options.keySet()) {
RuntimeValue value = new RuntimeValue(options.get(name), null, null);
xpipeline.passOption(name, value);
// Passing options was never documented and this is redundant with the behavior of posting
// to the base pipeline endoing, /pipelines/{id}
/*
if (MediaType.MULTIPART_FORM_DATA.equals(entity.getMediaType(), true)) {
try {
processMultipartForm(pipeconfig, entity, variant);
} catch (XProcException e) {
return badRequest(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage(), variant.getMediaType());
}
} else {
HashMap<QName,String> options = convertForm(getQuery());
for (QName name : options.keySet()) {
RuntimeValue value = new RuntimeValue(options.get(name), null, null);
xpipeline.passOption(name, value);
}
}
*/

return runPipeline(id);
}

0 comments on commit 93f2f2c

Please sign in to comment.
You can’t perform that action at this time.