You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/11/11 17:16:40 UTC
svn commit: r1540761 - in /cxf/trunk:
core/src/main/java/org/apache/cxf/attachment/
core/src/test/java/org/apache/cxf/attachment/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/
rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/e...
Author: sergeyb
Date: Mon Nov 11 16:16:39 2013
New Revision: 1540761
URL: http://svn.apache.org/r1540761
Log:
[CXF-5368] Using a dedicated Content-Disposition handler to avoid issues with filename parameters containing ';'
Added:
cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java (with props)
cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java (with props)
Modified:
cxf/trunk/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/ContentDisposition.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/multipart/ContentDispositionTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartStore.java
Modified: cxf/trunk/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
URL: http://svn.apache.org/viewvc/cxf/trunk/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java?rev=1540761&r1=1540760&r2=1540761&view=diff
==============================================================================
--- cxf/trunk/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java (original)
+++ cxf/trunk/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java Mon Nov 11 16:16:39 2013
@@ -37,7 +37,6 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
-import java.util.StringTokenizer;
import java.util.UUID;
import javax.activation.CommandInfo;
@@ -318,23 +317,7 @@ public final class AttachmentUtil {
final String ct = getHeader(headers, "Content-Type");
String cd = getHeader(headers, "Content-Disposition");
- String fileName = null;
- if (!StringUtils.isEmpty(cd)) {
- StringTokenizer token = new StringTokenizer(cd, ";");
- while (token.hasMoreElements()) {
- fileName = token.nextToken();
- if (fileName.startsWith("name=")) {
- break;
- }
- }
- if (!StringUtils.isEmpty(fileName)) {
- if (fileName.contains("\"")) {
- fileName = fileName.substring(fileName.indexOf("\"") + 1, fileName.lastIndexOf("\""));
- } else {
- fileName = fileName.substring(fileName.indexOf("=") + 1);
- }
- }
- }
+ String fileName = getContentDispositionFileName(cd);
String encoding = null;
@@ -360,6 +343,13 @@ public final class AttachmentUtil {
return att;
}
+ static String getContentDispositionFileName(String cd) {
+ if (StringUtils.isEmpty(cd)) {
+ return null;
+ }
+ //TODO: save ContentDisposition directly
+ return new ContentDisposition(cd).getParameter("filename");
+ }
public static InputStream decode(InputStream in, String encoding) throws IOException {
encoding = encoding.toLowerCase();
Added: cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java
URL: http://svn.apache.org/viewvc/cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java?rev=1540761&view=auto
==============================================================================
--- cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java (added)
+++ cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java Mon Nov 11 16:16:39 2013
@@ -0,0 +1,71 @@
+/**
+ * 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.cxf.attachment;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ContentDisposition {
+ private static final String CD_HEADER_PARAMS_EXPRESSION =
+ "(([\\w]+( )?=( )?\"[^\"]+\")|([\\w]+( )?=( )?[^;]+))";
+ private static final Pattern CD_HEADER_PARAMS_PATTERN =
+ Pattern.compile(CD_HEADER_PARAMS_EXPRESSION);
+ private String value;
+ private String type;
+ private Map<String, String> params = new LinkedHashMap<String, String>();
+
+ public ContentDisposition(String value) {
+ this.value = value;
+
+ String tempValue = value;
+
+ int index = tempValue.indexOf(';');
+ if (index > 0 && !(tempValue.indexOf('=') < index)) {
+ type = tempValue.substring(0, index).trim();
+ tempValue = tempValue.substring(index + 1);
+ }
+
+ Matcher m = CD_HEADER_PARAMS_PATTERN.matcher(tempValue);
+ while (m.find()) {
+ String[] pair = m.group().trim().split("=");
+ params.put(pair[0].trim(),
+ pair.length == 2 ? pair[1].trim().replace("\"", "") : "");
+ }
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getParameter(String name) {
+ return params.get(name);
+ }
+
+ public Map<String, String> getParameters() {
+ return Collections.unmodifiableMap(params);
+ }
+
+ public String toString() {
+ return value;
+ }
+}
Propchange: cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/core/src/main/java/org/apache/cxf/attachment/ContentDisposition.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java?rev=1540761&view=auto
==============================================================================
--- cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java (added)
+++ cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java Mon Nov 11 16:16:39 2013
@@ -0,0 +1,76 @@
+/**
+ * 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.cxf.attachment;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AttachmentUtilTest extends Assert {
+
+ @Test
+ public void testContendDispositionFileNameNoQuotes() {
+ assertEquals("a.txt",
+ AttachmentUtil.getContentDispositionFileName("form-data; filename=a.txt"));
+ }
+
+ @Test
+ public void testContendDispositionFileNameNoQuotesAndType() {
+ assertEquals("a.txt",
+ AttachmentUtil.getContentDispositionFileName("filename=a.txt"));
+ }
+
+ @Test
+ public void testContendDispositionFileNameNoQuotesAndType2() {
+ assertEquals("a.txt",
+ AttachmentUtil.getContentDispositionFileName("name=files; filename=a.txt"));
+ }
+
+ @Test
+ public void testContendDispositionFileNameSpacesNoQuotes() {
+ assertEquals("a.txt",
+ AttachmentUtil.getContentDispositionFileName("form-data; filename = a.txt"));
+ }
+
+ @Test
+ public void testContendDispositionFileNameWithQuotes() {
+ assertEquals("a.txt",
+ AttachmentUtil.getContentDispositionFileName("form-data; filename=\"a.txt\""));
+ }
+
+ @Test
+ public void testContendDispositionFileNameWithQuotesAndSemicolon() {
+ assertEquals("a;txt",
+ AttachmentUtil.getContentDispositionFileName("form-data; filename=\"a;txt\""));
+ }
+
+ @Test
+ public void testContendDispositionFileNameWithQuotesAndSemicolon2() {
+ assertEquals("a;txt",
+ AttachmentUtil.getContentDispositionFileName("filename=\"a;txt\""));
+ }
+
+ @Test
+ public void testContendDispositionFileNameWithQuotesAndSemicolon3() {
+ assertEquals("a;txt",
+ AttachmentUtil.getContentDispositionFileName("name=\"a\";filename=\"a;txt\""));
+ }
+
+
+}
+
Propchange: cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/core/src/test/java/org/apache/cxf/attachment/AttachmentUtilTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/ContentDisposition.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/ContentDisposition.java?rev=1540761&r1=1540760&r2=1540761&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/ContentDisposition.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/multipart/ContentDisposition.java Mon Nov 11 16:16:39 2013
@@ -19,57 +19,10 @@
package org.apache.cxf.jaxrs.ext.multipart;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.cxf.common.util.StringUtils;
-
-public class ContentDisposition {
-
- private List<String> values;
+public class ContentDisposition extends org.apache.cxf.attachment.ContentDisposition {
public ContentDisposition(String value) {
- values = Arrays.asList(StringUtils.split(value, ";"));
- }
-
- public String getType() {
- return values.get(0).trim();
- }
-
- public String getParameter(String name) {
- for (int i = 1; i < values.size(); i++) {
- String v = values.get(i).trim();
- if (v.startsWith(name)) {
- String[] parts = StringUtils.split(v, "=");
- return parts.length == 2 ? parts[1].trim().replace("\"", "").replace("'", "") : "";
- }
- }
- return null;
- }
-
- public Map<String, String> getParameters() {
- Map<String, String> map = new LinkedHashMap<String, String>();
- for (int i = 1; i < values.size(); i++) {
- String[] parts = StringUtils.split(values.get(i), "=");
- map.put(parts[0].trim(), parts.length == 2
- ? parts[1].trim().replace("\"", "").replace("'", "") : "");
- }
- return map;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < values.size(); i++) {
- if (values.get(i).length() == 0) {
- continue;
- }
- sb.append(values.get(i));
- if (i + 1 < values.size()) {
- sb.append(';');
- }
- }
- return sb.toString();
+ super(value);
}
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/multipart/ContentDispositionTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/multipart/ContentDispositionTest.java?rev=1540761&r1=1540760&r2=1540761&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/multipart/ContentDispositionTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/multipart/ContentDispositionTest.java Mon Nov 11 16:16:39 2013
@@ -32,5 +32,19 @@ public class ContentDispositionTest exte
assertEquals("foo", cd.getParameter("bar"));
assertEquals("baz1", cd.getParameter("baz"));
}
+ @Test
+ public void testContentDispositionWithQuotes() {
+ ContentDisposition cd = new ContentDisposition(" attachment ; bar=\"foo.txt\" ; baz = baz1");
+ assertEquals("attachment", cd.getType());
+ assertEquals("foo.txt", cd.getParameter("bar"));
+ assertEquals("baz1", cd.getParameter("baz"));
+ }
+ @Test
+ public void testContentDispositionWithQuotesAndSemicolon() {
+ ContentDisposition cd = new ContentDisposition(" attachment ; bar=\"foo;txt\" ; baz = baz1");
+ assertEquals("attachment", cd.getType());
+ assertEquals("foo;txt", cd.getParameter("bar"));
+ assertEquals("baz1", cd.getParameter("baz"));
+ }
}
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java?rev=1540761&r1=1540760&r2=1540761&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java Mon Nov 11 16:16:39 2013
@@ -20,6 +20,7 @@
package org.apache.cxf.systest.jaxrs;
import java.awt.Image;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.annotation.Annotation;
@@ -669,6 +670,23 @@ public class JAXRSMultipartTest extends
}
@Test
+ public void testUploadFileWithSemicolonName() throws Exception {
+ String address = "http://localhost:" + PORT + "/bookstore/books/file/semicolon";
+ WebClient client = WebClient.create(address);
+ client.type("multipart/form-data").accept("text/plain");
+
+ ContentDisposition cd = new ContentDisposition("attachment;name=\"a\";filename=\"a;txt\"");
+ MultivaluedMap<String, String> headers = new MetadataMap<String, String>();
+ headers.putSingle("Content-Disposition", cd.toString());
+ Attachment att = new Attachment(new ByteArrayInputStream("file name with semicolon".getBytes()),
+ headers);
+
+ MultipartBody body = new MultipartBody(att);
+ String partContent = client.post(body, String.class);
+ assertEquals("file name with semicolon, filename:" + "a;txt", partContent);
+ }
+
+ @Test
public void testUploadImageFromForm2() throws Exception {
File file =
new File(getClass().getResource("/org/apache/cxf/systest/jaxrs/resources/java.jpg")
Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartStore.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartStore.java?rev=1540761&r1=1540760&r2=1540761&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartStore.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartStore.java Mon Nov 11 16:16:39 2013
@@ -142,6 +142,15 @@ public class MultipartStore {
return image;
}
+ @Path("/books/file/semicolon")
+ @Consumes("multipart/form-data")
+ @Produces("text/plain")
+ @POST
+ public String addBookFileNameSemicolon(@Multipart("a") Attachment att) {
+ return att.getObject(String.class)
+ + ", filename:" + att.getContentDisposition().getParameter("filename");
+ }
+
@POST
@Path("/books/formimage")
@Consumes("multipart/form-data")