From 1ff665f76ac38faaa8831191b6b4be89fc1b2acf Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 24 Jun 2013 13:00:21 +1000 Subject: [PATCH 1/4] Code cleanups for direct RequestDispatcher access --- .../java/org/eclipse/jetty/server/Response.java | 9 +++++---- .../eclipse/jetty/servlet/ServletHandler.java | 16 +++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 272955324c0..2ab4e6c9f09 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Locale; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @@ -341,10 +342,10 @@ public class Response implements HttpServletResponse error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class); if (error_handler!=null) { - request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code)); - request.setAttribute(Dispatcher.ERROR_MESSAGE, message); - request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI()); - request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName()); + request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code)); + request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); + request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); + request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName()); error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this ); } else diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 14e5fe054ca..05d0ce25ee8 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -24,20 +24,19 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; -import java.util.ListIterator; -import java.util.Set; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; -import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -58,7 +57,6 @@ import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Dispatcher; -import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServletRequestHttpWrapper; @@ -393,8 +391,8 @@ public class ServletHandler extends ScopedHandler if (DispatcherType.INCLUDE.equals(type)) { - baseRequest.setAttribute(Dispatcher.INCLUDE_SERVLET_PATH,servlet_path); - baseRequest.setAttribute(Dispatcher.INCLUDE_PATH_INFO, path_info); + baseRequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH,servlet_path); + baseRequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, path_info); } else { @@ -562,8 +560,8 @@ public class ServletHandler extends ScopedHandler if (!response.isCommitted()) { - request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); - request.setAttribute(Dispatcher.ERROR_EXCEPTION,th); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th); if (th instanceof UnavailableException) { UnavailableException ue = (UnavailableException)th; From b2b2ce25fc5caa7383a78600d0bfa070370f237b Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 24 Jun 2013 13:11:04 +1000 Subject: [PATCH 2/4] Revert "Code cleanups for direct RequestDispatcher access" This reverts commit 1ff665f76ac38faaa8831191b6b4be89fc1b2acf. --- .../java/org/eclipse/jetty/server/Response.java | 9 ++++----- .../eclipse/jetty/servlet/ServletHandler.java | 16 +++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 2ab4e6c9f09..272955324c0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -26,7 +26,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Locale; -import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @@ -342,10 +341,10 @@ public class Response implements HttpServletResponse error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class); if (error_handler!=null) { - request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code)); - request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); - request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); - request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName()); + request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code)); + request.setAttribute(Dispatcher.ERROR_MESSAGE, message); + request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI()); + request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName()); error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this ); } else diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 05d0ce25ee8..14e5fe054ca 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -24,19 +24,20 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; import java.util.ListIterator; +import java.util.Set; +import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; +import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; -import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -57,6 +58,7 @@ import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Dispatcher; +import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServletRequestHttpWrapper; @@ -391,8 +393,8 @@ public class ServletHandler extends ScopedHandler if (DispatcherType.INCLUDE.equals(type)) { - baseRequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH,servlet_path); - baseRequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, path_info); + baseRequest.setAttribute(Dispatcher.INCLUDE_SERVLET_PATH,servlet_path); + baseRequest.setAttribute(Dispatcher.INCLUDE_PATH_INFO, path_info); } else { @@ -560,8 +562,8 @@ public class ServletHandler extends ScopedHandler if (!response.isCommitted()) { - request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); - request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th); + request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); + request.setAttribute(Dispatcher.ERROR_EXCEPTION,th); if (th instanceof UnavailableException) { UnavailableException ue = (UnavailableException)th; From 068e67a8df4d65d1c3645659ffb8e2582171b7a1 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 24 Jun 2013 13:13:03 +1000 Subject: [PATCH 3/4] Code cleanups for direct RequestDispatcher access --- .../src/main/java/org/eclipse/jetty/server/Response.java | 9 +++++---- .../java/org/eclipse/jetty/servlet/ServletHandler.java | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 272955324c0..2ab4e6c9f09 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Locale; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @@ -341,10 +342,10 @@ public class Response implements HttpServletResponse error_handler = _connection.getConnector().getServer().getBean(ErrorHandler.class); if (error_handler!=null) { - request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(code)); - request.setAttribute(Dispatcher.ERROR_MESSAGE, message); - request.setAttribute(Dispatcher.ERROR_REQUEST_URI, request.getRequestURI()); - request.setAttribute(Dispatcher.ERROR_SERVLET_NAME,request.getServletName()); + request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(code)); + request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); + request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); + request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,request.getServletName()); error_handler.handle(null,_connection.getRequest(),_connection.getRequest(),this ); } else diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 14e5fe054ca..9aff148ce98 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -38,6 +38,7 @@ import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -562,8 +563,8 @@ public class ServletHandler extends ScopedHandler if (!response.isCommitted()) { - request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); - request.setAttribute(Dispatcher.ERROR_EXCEPTION,th); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass()); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th); if (th instanceof UnavailableException) { UnavailableException ue = (UnavailableException)th; @@ -588,8 +589,8 @@ public class ServletHandler extends ScopedHandler // TODO httpResponse.getHttpConnection().forceClose(); if (!response.isCommitted()) { - request.setAttribute(Dispatcher.ERROR_EXCEPTION_TYPE,e.getClass()); - request.setAttribute(Dispatcher.ERROR_EXCEPTION,e); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass()); + request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } else From 0daddd1a3acf1609169de229b1f33aa2307ce981 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 24 Jun 2013 16:20:04 +1000 Subject: [PATCH 4/4] 411458 MultiPartFilter getParameterMap doesn't preserve multivalued parameters 411459 MultiPartFilter.Wrapper getParameter should use charset encoding of part --- .../jetty/servlets/MultiPartFilter.java | 32 +++++++-- .../jetty/servlets/MultipartFilterTest.java | 72 +++++++++++++++++-- .../org/eclipse/jetty/testing/HttpTester.java | 9 +++ 3 files changed, 103 insertions(+), 10 deletions(-) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java index c872e936faa..f8d2d3e8b1d 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java @@ -48,12 +48,15 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.ReadLineInputStream; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -513,12 +516,11 @@ public class MultiPartFilter implements Filter { try { - String s=new String((byte[])o,_encoding); - return s; + return getParameterBytesAsString(name, (byte[])o); } catch(Exception e) { - e.printStackTrace(); + LOG.warn(e); } } else if (o!=null) @@ -533,11 +535,11 @@ public class MultiPartFilter implements Filter @Override public Map getParameterMap() { - Map cmap = new HashMap(); + Map cmap = new HashMap(); for ( Object key : _params.keySet() ) { - cmap.put((String)key,getParameter((String)key)); + cmap.put((String)key,getParameterValues((String)key)); } return Collections.unmodifiableMap(cmap); @@ -571,7 +573,7 @@ public class MultiPartFilter implements Filter { try { - v[i]=new String((byte[])o,_encoding); + v[i]=getParameterBytesAsString(name, (byte[])o); } catch(Exception e) { @@ -594,6 +596,24 @@ public class MultiPartFilter implements Filter { _encoding=enc; } + + + /* ------------------------------------------------------------------------------- */ + private String getParameterBytesAsString (String name, byte[] bytes) + throws UnsupportedEncodingException + { + //check if there is a specific encoding for the parameter + Object ct = _params.get(name+CONTENT_TYPE_SUFFIX); + //use default if not + String contentType = _encoding; + if (ct != null) + { + String tmp = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer((String)ct)); + contentType = (tmp == null?_encoding:tmp); + } + + return new String(bytes,contentType); + } } private static class Base64InputStream extends InputStream diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java index 5f12d70442c..a610a0f3705 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java @@ -21,21 +21,26 @@ package org.eclipse.jetty.servlets; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Array; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterMapping; import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.StringUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -747,7 +752,7 @@ public class MultipartFilterTest assertTrue(response.getContent().contains("aaaa,bbbbb")); } - + /* * see the testParameterMap test * @@ -758,13 +763,12 @@ public class MultipartFilterTest @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String content = (String)req.getParameterMap().get("\"strup\"Content-Type: application/octet-stream"); + String content = (String)req.getParameter("\"strup\"Content-Type: application/octet-stream"); assertThat(content, containsString("How now brown cow.")); super.doPost(req, resp); - } - + } } /** @@ -809,6 +813,66 @@ public class MultipartFilterTest assertTrue(response.getContent().indexOf("brown cow")>=0); } + + public static class TestServletCharSet extends HttpServlet + { + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + //test that the multipart content bytes were converted correctly from their charset to unicode + String content = (String)req.getParameter("ttt"); + assertNotNull(content); + assertEquals("ttt\u01FCzzz",content); + assertEquals("application/octet-stream; charset=UTF-8",req.getParameter("ttt"+MultiPartFilter.CONTENT_TYPE_SUFFIX)); + + + //test that the parameter map retrieves values as String[] + Map map = req.getParameterMap(); + Object o = map.get("ttt"); + assertTrue(o.getClass().isArray()); + super.doPost(req, resp); + } + } + + + @Test + public void testWithCharSet() + throws Exception + { + // generated and parsed test + HttpTester request = new HttpTester() { + + }; + HttpTester response = new HttpTester(); + + tester.addServlet(TestServletCharSet.class,"/test2"); + + // test GET + request.setMethod("POST"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setURI("/context/test2"); + + String boundary="XyXyXy"; + request.setHeader("Content-Type","multipart/form-data; boundary="+boundary); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + baos.write(("--" + boundary + "\r\n"+ + "Content-Disposition: form-data; name=\"ttt\"\r\n"+ + "Content-Type: application/octet-stream; charset=UTF-8\r\n\r\n").getBytes()); + baos.write("ttt\u01FCzzz".getBytes(StringUtil.__UTF8)); + baos.write(("\r\n--" + boundary + "--\r\n\r\n").getBytes()); + + request.setContentBytes(baos.toByteArray()); + + response.parse(tester.getResponses(new ByteArrayBuffer(request.generate().getBytes(StringUtil.__UTF8))).toString()); + } + + + + public static class DumpServlet extends HttpServlet { private static final long serialVersionUID = 201012011130L; diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java index 67ed36b4d11..422334b11e2 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java @@ -531,6 +531,15 @@ public class HttpTester _genContent=null; } } + + /* ------------------------------------------------------------ */ + public void setContentBytes(byte[] bytes) + { + _parsedContent = null; + _genContent = bytes; + setLongHeader(HttpHeaders.CONTENT_LENGTH, bytes.length); + + } /* ------------------------------------------------------------ */ private class PH extends HttpParser.EventHandler