Repository: tomee Updated Branches: refs/heads/master 3e2fe0af9 -> 481fc0516
TOMEE-1715 basic Part support in openejb-http Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/481fc051 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/481fc051 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/481fc051 Branch: refs/heads/master Commit: 481fc05169a57af8fe52a7f0ed89bf9d77c57d27 Parents: 3e2fe0a Author: Romain manni-Bucau <rmannibu...@gmail.com> Authored: Fri Feb 19 19:04:22 2016 +0100 Committer: Romain manni-Bucau <rmannibu...@gmail.com> Committed: Fri Feb 19 19:04:22 2016 +0100 ---------------------------------------------------------------------- server/openejb-http/pom.xml | 7 ++ .../openejb/server/httpd/HttpRequestImpl.java | 27 ++++- .../httpd/part/CommonsFileUploadPart.java | 117 +++++++++++++++++++ .../part/CommonsFileUploadPartFactory.java | 91 +++++++++++++++ 4 files changed, 237 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/481fc051/server/openejb-http/pom.xml ---------------------------------------------------------------------- diff --git a/server/openejb-http/pom.xml b/server/openejb-http/pom.xml index 630220c..a351213 100644 --- a/server/openejb-http/pom.xml +++ b/server/openejb-http/pom.xml @@ -139,6 +139,13 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> + + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.3.1</version> + <optional>true</optional> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/tomee/blob/481fc051/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java ---------------------------------------------------------------------- diff --git a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java index fa2428c..28a9f47 100644 --- a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java +++ b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java @@ -21,6 +21,7 @@ import org.apache.openejb.assembler.classic.Assembler; import org.apache.openejb.assembler.classic.WebAppInfo; import org.apache.openejb.core.WebContext; import org.apache.openejb.loader.SystemInstance; +import org.apache.openejb.server.httpd.part.CommonsFileUploadPartFactory; import org.apache.openejb.server.httpd.session.SessionManager; import org.apache.openejb.spi.SecurityService; import org.apache.openejb.util.ArrayEnumeration; @@ -69,6 +70,7 @@ import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpUpgradeHandler; import javax.servlet.http.Part; +import static java.util.Arrays.asList; import static java.util.Collections.singletonList; /** @@ -77,6 +79,7 @@ import static java.util.Collections.singletonList; */ public class HttpRequestImpl implements HttpRequest { private static final String FORM_URL_ENCODED = "application/x-www-form-urlencoded"; + private static final String MULTIPART_FORM_DATA = "multipart/form-data"; private static final String TRANSFER_ENCODING = "Transfer-Encoding"; private static final String CHUNKED = "chunked"; @@ -122,7 +125,7 @@ public class HttpRequestImpl implements HttpRequest { */ private final Map<String, List<String>> parameters = new HashMap<>(); - private final Map<String, Part> parts = new HashMap<>(); + private volatile Collection<Part> parts; /** * Cookies sent from the client @@ -217,7 +220,15 @@ public class HttpRequestImpl implements HttpRequest { @Override public Part getPart(String s) throws IOException, ServletException { - return parts.get(s); + getParts(); // ensure it is initialized + if (parts != null) { + for (final Part p : parts) { + if (s.equals(p.getName())) { + return p; + } + } + } + return null; } @Override @@ -227,7 +238,10 @@ public class HttpRequestImpl implements HttpRequest { @Override public Collection<Part> getParts() throws IOException, ServletException { - return parts.values(); + if (parts == null) { // assume it is not init + parts = CommonsFileUploadPartFactory.read(this); + } + return parts; } public void noPathInfo() { // todo: enhance it @@ -662,7 +676,7 @@ public class HttpRequestImpl implements HttpRequest { contentType = getHeader(HttpRequest.HEADER_CONTENT_TYPE); final boolean hasBody = hasBody(); - if (hasBody && contentType != null && contentType.startsWith(FORM_URL_ENCODED)) { + if (hasBody && contentType != null && (contentType.startsWith(FORM_URL_ENCODED) || contentType.startsWith(MULTIPART_FORM_DATA))) { String rawParams; try { @@ -696,7 +710,6 @@ public class HttpRequestImpl implements HttpRequest { value = ""; formParams.put(name, value); - //System.out.println(name + ": " + value); } } else if (hasBody && CHUNKED.equals(headers.get(TRANSFER_ENCODING))) { try { @@ -1029,6 +1042,10 @@ public class HttpRequestImpl implements HttpRequest { new WebBeansFilter.AsynContextWrapper(asyncContext, servletRequest, webBeansContext) : asyncContext; } + public void addInternalParameter(final String key, final String val) { + parameters.put(key, asList(val)); + } + public String getParameter(String name) { final List<String> strings = parameters.get(name); return strings == null ? null : strings.iterator().next(); http://git-wip-us.apache.org/repos/asf/tomee/blob/481fc051/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPart.java ---------------------------------------------------------------------- diff --git a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPart.java b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPart.java new file mode 100644 index 0000000..a056360 --- /dev/null +++ b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPart.java @@ -0,0 +1,117 @@ +/* +* 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.openejb.server.httpd.part; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItem; + +import javax.servlet.http.Part; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +// highly inspired from tomcat +public class CommonsFileUploadPart implements Part { + private final FileItem fileItem; + private final File location; + + public CommonsFileUploadPart(final FileItem fileItem, final File location) { + this.fileItem = fileItem; + this.location = location; + } + + @Override + public void delete() throws IOException { + fileItem.delete(); + } + + @Override + public String getContentType() { + return fileItem.getContentType(); + } + + @Override + public String getHeader(final String name) { + return fileItem.getHeaders().getHeader(name); + } + + @Override + public Collection<String> getHeaderNames() { + if (fileItem instanceof DiskFileItem) { + final Set<String> headerNames = new LinkedHashSet<>(); + final Iterator<String> iter = fileItem.getHeaders().getHeaderNames(); + while (iter.hasNext()) { + headerNames.add(iter.next()); + } + return headerNames; + } + return Collections.emptyList(); + } + + @Override + public Collection<String> getHeaders(final String name) { + final Set<String> headers = new LinkedHashSet<>(); + final Iterator<String> iter = fileItem.getHeaders().getHeaders(name); + while (iter.hasNext()) { + headers.add(iter.next()); + } + return headers; + } + + @Override + public InputStream getInputStream() throws IOException { + return fileItem.getInputStream(); + } + + @Override + public String getName() { + return fileItem.getFieldName(); + } + + @Override + public long getSize() { + return fileItem.getSize(); + } + + @Override + public void write(final String fileName) throws IOException { + File file = new File(fileName); + if (!file.isAbsolute()) { + file = new File(location, fileName); + } + try { + fileItem.write(file); + } catch (Exception e) { + throw new IOException(e); + } + } + + public String getString(final String encoding) throws UnsupportedEncodingException { + return fileItem.getString(encoding); + } + + @Override + public String getSubmittedFileName() { + return fileItem.getName(); + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/481fc051/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPartFactory.java ---------------------------------------------------------------------- diff --git a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPartFactory.java b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPartFactory.java new file mode 100644 index 0000000..309498d --- /dev/null +++ b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/part/CommonsFileUploadPartFactory.java @@ -0,0 +1,91 @@ +package org.apache.openejb.server.httpd.part; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload.servlet.ServletRequestContext; +import org.apache.openejb.loader.SystemInstance; +import org.apache.openejb.server.httpd.HttpRequestImpl; + +import javax.servlet.http.Part; +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static java.util.Arrays.asList; + +// [fileupload] is optional so using a class to lazy load the deps +public final class CommonsFileUploadPartFactory { + private static final File REPO; + + static { // TODO: move this config in http service if this code is useful + String repo = SystemInstance.get().getProperty("tomee.embedded.http.file.repository"); + if (repo == null) { + for (final String potential : asList("work", "temp", "target", "build")) { + try { + final File directory = SystemInstance.get().getBase().getDirectory(potential); + if (directory.isDirectory()) { + repo = directory.getAbsolutePath(); + break; + } + } catch (IOException e) { + // try next + } + } + } + REPO = new File(repo == null ? "." : repo); + } + + private CommonsFileUploadPartFactory() { + // no-op + } + + public static Collection<Part> read(final HttpRequestImpl request) { // mainly for testing + // Create a new file upload handler + final DiskFileItemFactory factory = new DiskFileItemFactory(); + factory.setRepository(REPO); + + final ServletFileUpload upload = new ServletFileUpload(); + upload.setFileItemFactory(factory); + + final List<Part> parts = new ArrayList<>(); + try { + final List<FileItem> items = upload.parseRequest(new ServletRequestContext(request)); + final String enc = request.getCharacterEncoding(); + for (final FileItem item : items) { + final CommonsFileUploadPart part = new CommonsFileUploadPart(item, null); + parts.add(part); + if (part.getSubmittedFileName() == null) { + String name = part.getName(); + String value = null; + try { + String encoding = request.getCharacterEncoding(); + if (encoding == null) { + if (enc == null) { + encoding = "UTF-8"; + } else { + encoding = enc; + } + } + value = part.getString(encoding); + } catch (final UnsupportedEncodingException uee) { + try { + value = part.getString("UTF-8"); + } catch (final UnsupportedEncodingException e) { + // not possible + } + } + request.addInternalParameter(name, value); + } + } + + return parts; + } catch (final FileUploadException e) { + throw new IllegalStateException(e); + } + } +}