Bug 475291 - [equinox jetty] doesn't support the servlet 3.0 multipart API
Signed-off-by: Raymond Auge <raymond.auge@liferay.com>
diff --git a/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java b/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
index 358d275..2d8ef58 100644
--- a/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
+++ b/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
@@ -129,6 +129,7 @@
ServletContextHandler httpContext = createHttpContext(dictionary);
if (null != customizer)
httpContext = (ServletContextHandler) customizer.customizeContext(httpContext, dictionary);
+ setupMultiPartConfig(dictionary, holder);
httpContext.addServlet(holder, "/*"); //$NON-NLS-1$
server.setHandler(httpContext);
@@ -422,4 +423,10 @@
}
return directory.delete();
}
+
+ private void setupMultiPartConfig(@SuppressWarnings("rawtypes") Dictionary dictionary, ServletHolder holder) {
+ MultipartConfigElement multipartConfigElement = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
+ holder.getRegistration().setMultipartConfig(multipartConfigElement);
+ }
+
}
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
index e95db54..acfa623 100644
--- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
@@ -62,6 +62,7 @@
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;
+import javax.servlet.http.Part;
import junit.framework.TestCase;
@@ -1859,6 +1860,100 @@
Assert.assertEquals("p=3&p=4&p=1&p=2|p=1&p=2|3|[3, 4, 1, 2]", result);
}
+ private static String getSubmittedFileName(Part part) {
+ for (String cd : part.getHeader("content-disposition").split(";")) {
+ if (cd.trim().startsWith("filename")) {
+ String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
+ return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
+ }
+ }
+ return null;
+ }
+
+ /*
+ * 3.1 file uploads
+ */
+ public void test_Servlet16() throws Exception {
+ Servlet servlet = new HttpServlet() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException, ServletException {
+
+ Part part = req.getPart("file");
+ Assert.assertNotNull(part);
+
+ String submittedFileName = part.getSubmittedFileName();
+ String contentType = part.getContentType();
+ long size = part.getSize();
+
+ PrintWriter writer = resp.getWriter();
+
+ writer.write(submittedFileName);
+ writer.write("|");
+ writer.write(contentType);
+ writer.write("|" + size);
+ }
+ };
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, "S16");
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/Servlet16/*");
+ registrations.add(getBundleContext().registerService(Servlet.class, servlet, props));
+
+ Map<String, List<Object>> map = new HashMap<String, List<Object>>();
+
+ map.put("file", Arrays.<Object>asList(getClass().getResource("resource1.txt")));
+
+ Map<String, List<String>> result = requestAdvisor.upload("Servlet16/do", map);
+
+ Assert.assertEquals("200", result.get("responseCode").get(0));
+ Assert.assertEquals("resource1.txt|text/plain|1", result.get("responseBody").get(0));
+ }
+
+ /*
+ * 3.0 file uploads
+ */
+ public void test_Servlet17() throws Exception {
+ Servlet servlet = new HttpServlet() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException, ServletException {
+
+ Part part = req.getPart("file");
+ Assert.assertNotNull(part);
+
+ String submittedFileName = getSubmittedFileName(part);
+ String contentType = part.getContentType();
+ long size = part.getSize();
+
+ PrintWriter writer = resp.getWriter();
+
+ writer.write(submittedFileName);
+ writer.write("|");
+ writer.write(contentType);
+ writer.write("|" + size);
+ }
+ };
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME, "S16");
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/Servlet16/*");
+ registrations.add(getBundleContext().registerService(Servlet.class, servlet, props));
+
+ Map<String, List<Object>> map = new HashMap<String, List<Object>>();
+
+ map.put("file", Arrays.<Object>asList(getClass().getResource("blue.png")));
+
+ Map<String, List<String>> result = requestAdvisor.upload("Servlet16/do", map);
+
+ Assert.assertEquals("200", result.get("responseCode").get(0));
+ Assert.assertEquals("blue.png|image/png|292", result.get("responseBody").get(0));
+ }
+
public void test_ServletContext1() throws Exception {
String expected = "/org/eclipse/equinox/http/servlet/tests/tb1/resource1.txt";
String actual;
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/blue.png b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/blue.png
new file mode 100644
index 0000000..f1ad5b2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/blue.png
Binary files differ
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java
index ec7c80d..9fdc89c 100644
--- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/util/ServletRequestAdvisor.java
@@ -13,9 +13,13 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.net.URLConnection;
import java.util.Arrays;
import java.util.Collections;
@@ -132,4 +136,119 @@
stream.close();
}
}
+
+ public Map<String, List<String>> upload(String value, Map<String, List<Object>> headers) throws IOException {
+ String spec = createUrlSpec(value);
+ log("Requesting " + spec); //$NON-NLS-1$
+ URL url = new URL(spec);
+ HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+
+ connection.setInstanceFollowRedirects(false);
+ connection.setConnectTimeout(150 * 1000);
+ connection.setReadTimeout(150 * 1000);
+
+ if (headers != null) {
+ for(Map.Entry<String, List<Object>> entry : headers.entrySet()) {
+ for(Object entryValue : entry.getValue()) {
+ if (entryValue instanceof String) {
+ connection.setRequestProperty(entry.getKey(), (String)entryValue);
+ }
+ else if (entryValue instanceof URL) {
+ uploadFileConnection(connection, entry.getKey(), (URL)entryValue);
+ }
+ else {
+ throw new IllegalArgumentException("only supports strings and files");
+ }
+ }
+ }
+ }
+
+ int responseCode = connection.getResponseCode();
+
+ Map<String, List<String>> map = new HashMap<String, List<String>>(connection.getHeaderFields());
+ map.put("responseCode", Collections.singletonList(String.valueOf(responseCode)));
+
+ InputStream stream;
+
+ if (responseCode >= 400) {
+ stream = connection.getErrorStream();
+ }
+ else {
+ stream = connection.getInputStream();
+ }
+
+ try {
+ map.put("responseBody", Arrays.asList(drain(stream)));
+ return map;
+ } finally {
+ stream.close();
+ }
+ }
+
+ private void uploadFileConnection(HttpURLConnection connection, String param, URL file)
+ throws IOException {
+
+ String fileName = file.getPath();
+ fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
+ connection.setDoOutput(true);
+
+ String boundary = Long.toHexString(System.currentTimeMillis());
+ String CRLF = "\r\n";
+ connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+
+ InputStream input = null;
+ OutputStream output = null;
+ PrintWriter writer = null;
+
+ try {
+ output = connection.getOutputStream();
+ writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true);
+
+ writer.append("--" + boundary);
+ writer.append(CRLF);
+ writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"");
+ writer.append(fileName);
+ writer.append("\"");
+ writer.append(CRLF);
+ writer.append("Content-Type: ");
+ String contentType = URLConnection.guessContentTypeFromName(fileName);
+ writer.append(contentType);
+ writer.append(CRLF);
+ if (!contentType.startsWith("text/")) {
+ writer.append("Content-Transfer-Encoding: binary");
+ writer.append(CRLF);
+ }
+ writer.append(CRLF);
+ writer.flush();
+
+ byte[] buf = new byte[64];
+ input = file.openStream();
+ int c = 0;
+ while ((c = input.read(buf, 0, buf.length)) > 0) {
+ output.write(buf, 0, c);
+ output.flush();
+ }
+
+ output.flush(); // Important before continuing with writer!
+ writer.append(CRLF); // CRLF is important! It indicates end of boundary.
+ writer.flush();
+
+ // End of multipart/form-data.
+ writer.append("--" + boundary + "--");
+ writer.append(CRLF);
+ writer.flush();
+ }
+ finally {
+ if (input != null) {
+ input.close();
+ }
+ if (output != null) {
+ output.close();
+ }
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
}