File tree Expand file tree Collapse file tree
main/java/io/netty/handler/codec/http/multipart
test/java/io/netty/handler/codec/http/multipart Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1784,7 +1784,7 @@ private static String[] splitMultipartHeader(String sb) {
17841784 String svalue = sb .substring (valueStart , valueEnd );
17851785 String [] values ;
17861786 if (svalue .indexOf (';' ) >= 0 ) {
1787- values = StringUtil . split (svalue , ';' );
1787+ values = splitMultipartHeaderValues (svalue );
17881788 } else {
17891789 values = StringUtil .split (svalue , ',' );
17901790 }
@@ -1797,4 +1797,38 @@ private static String[] splitMultipartHeader(String sb) {
17971797 }
17981798 return array ;
17991799 }
1800+
1801+ /**
1802+ * Split one header value in Multipart
1803+ * @return an array of String where values that were separated by ';' or ','
1804+ */
1805+ private static String [] splitMultipartHeaderValues (String svalue ) {
1806+ List <String > values = new ArrayList <String >(1 );
1807+ boolean inQuote = false ;
1808+ boolean escapeNext = false ;
1809+ int start = 0 ;
1810+ for (int i = 0 ; i < svalue .length (); i ++) {
1811+ char c = svalue .charAt (i );
1812+ if (inQuote ) {
1813+ if (escapeNext ) {
1814+ escapeNext = false ;
1815+ } else {
1816+ if (c == '\\' ) {
1817+ escapeNext = true ;
1818+ } else if (c == '"' ) {
1819+ inQuote = false ;
1820+ }
1821+ }
1822+ } else {
1823+ if (c == '"' ) {
1824+ inQuote = true ;
1825+ } else if (c == ';' ) {
1826+ values .add (svalue .substring (start , i ));
1827+ start = i + 1 ;
1828+ }
1829+ }
1830+ }
1831+ values .add (svalue .substring (start ));
1832+ return values .toArray (new String [values .size ()]);
1833+ }
18001834}
Original file line number Diff line number Diff line change @@ -321,4 +321,30 @@ public void testChunkCorrect() throws Exception {
321321 decoder .offer (part3 );
322322 decoder .offer (part4 );
323323 }
324+
325+ // See https://github.com/netty/netty/issues/3326
326+ @ Test
327+ public void testFilenameContainingSemicolon () throws Exception {
328+ final String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO" ;
329+ final DefaultFullHttpRequest req = new DefaultFullHttpRequest (HttpVersion .HTTP_1_1 , HttpMethod .POST ,
330+ "http://localhost" );
331+ req .headers ().add (HttpHeaders .Names .CONTENT_TYPE , "multipart/form-data; boundary=" + boundary );
332+ // Force to use memory-based data.
333+ final DefaultHttpDataFactory inMemoryFactory = new DefaultHttpDataFactory (false );
334+ final String data = "asdf" ;
335+ final String filename = "tmp;0.txt" ;
336+ final String body =
337+ "--" + boundary + "\r \n " +
338+ "Content-Disposition: form-data; name=\" file\" ; filename=\" " + filename + "\" \r \n " +
339+ "Content-Type: image/gif\r \n " +
340+ "\r \n " +
341+ data + "\r \n " +
342+ "--" + boundary + "--\r \n " ;
343+
344+ req .content ().writeBytes (body .getBytes (CharsetUtil .UTF_8 .name ()));
345+ // Create decoder instance to test.
346+ final HttpPostRequestDecoder decoder = new HttpPostRequestDecoder (inMemoryFactory , req );
347+ assertFalse (decoder .getBodyHttpDatas ().isEmpty ());
348+ decoder .destroy ();
349+ }
324350}
You can’t perform that action at this time.
0 commit comments