killbill-memoizeit

jaxrs: revisit the form kludge in PluginResource It wasn't

5/24/2013 7:44:13 PM

Details

diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PluginResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PluginResource.java
index bd3462c..a36e94c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PluginResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PluginResource.java
@@ -20,7 +20,10 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URLEncoder;
 import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
@@ -31,6 +34,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.HEAD;
@@ -38,6 +42,7 @@ import javax.ws.rs.OPTIONS;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
+import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 
 import org.slf4j.Logger;
@@ -59,7 +64,8 @@ import com.google.inject.name.Named;
 public class PluginResource extends JaxRsResourceBase {
 
     private static final Logger log = LoggerFactory.getLogger(PluginResource.class);
-    private static final Charset UTF_8 = Charset.forName("UTF-8");
+    private static final String UTF_8_STRING = "UTF-8";
+    private static final Charset UTF_8 = Charset.forName(UTF_8_STRING);
 
     private final HttpServlet osgiServlet;
 
@@ -99,6 +105,16 @@ public class PluginResource extends JaxRsResourceBase {
     }
 
     @POST
+    @Consumes("application/x-www-form-urlencoded")
+    public Response doFormPOST(final MultivaluedMap<String, String> form,
+                               @javax.ws.rs.core.Context final HttpServletRequest request,
+                               @javax.ws.rs.core.Context final HttpServletResponse response,
+                               @javax.ws.rs.core.Context final ServletContext servletContext,
+                               @javax.ws.rs.core.Context final ServletConfig servletConfig) throws ServletException, IOException {
+        return serviceViaOSGIPlugin(form, request, response, servletContext, servletConfig);
+    }
+
+    @POST
     public Response doPOST(@javax.ws.rs.core.Context final HttpServletRequest request,
                            @javax.ws.rs.core.Context final HttpServletResponse response,
                            @javax.ws.rs.core.Context final ServletContext servletContext,
@@ -127,8 +143,21 @@ public class PluginResource extends JaxRsResourceBase {
 
     private Response serviceViaOSGIPlugin(final HttpServletRequest request, final HttpServletResponse response,
                                           final ServletContext servletContext, final ServletConfig servletConfig) throws ServletException, IOException {
+        return serviceViaOSGIPlugin(request, request.getInputStream(), response, servletContext, servletConfig);
+    }
+
+    private Response serviceViaOSGIPlugin(final MultivaluedMap<String, String> form,
+                                          final HttpServletRequest request, final HttpServletResponse response,
+                                          final ServletContext servletContext, final ServletConfig servletConfig) throws ServletException, IOException {
+        // form will contain form parameters, if any. Even if the request contains such parameters, it may be empty
+        // if a filter (e.g. Shiro) has already consumed them (see kludge below)
+        return serviceViaOSGIPlugin(request, createInputStream(request, form), response, servletContext, servletConfig);
+    }
+
+    private Response serviceViaOSGIPlugin(final HttpServletRequest request, final InputStream inputStream, final HttpServletResponse response,
+                                          final ServletContext servletContext, final ServletConfig servletConfig) throws ServletException, IOException {
         prepareOSGIRequest(request, servletContext, servletConfig);
-        osgiServlet.service(new OSGIServletRequestWrapper(request, createInputStream(request)), new OSGIServletResponseWrapper(response));
+        osgiServlet.service(new OSGIServletRequestWrapper(request, inputStream), new OSGIServletResponseWrapper(response));
 
         if (response.isCommitted()) {
             if (response.getStatus() >= 400) {
@@ -141,32 +170,41 @@ public class PluginResource extends JaxRsResourceBase {
         }
     }
 
-    private InputStream createInputStream(final HttpServletRequest request) throws IOException {
+    private InputStream createInputStream(final HttpServletRequest request, final MultivaluedMap<String, String> form) throws IOException {
         // /!\ Kludge alert (pierre) /!\
         // This is awful... But because of various servlet filters we have in place, include Shiro,
         // the request parameters and/or body at this point have already been looked at.
         // We can't use @FormParam in PluginResource because we don't know the form parameter names
         // in advance.
         // So... We just stick them back in :-)
-        // TODO Support x-www-form-urlencoded vs multipart/form-data
+        // TODO Support application/x-www-form-urlencoded vs multipart/form-data
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        final Map<String, String> data = new HashMap<String, String>();
         for (final String key : request.getParameterMap().keySet()) {
-            out.write((key + "=").getBytes(UTF_8));
-
-            int idx = 0;
-            for (final String value : request.getParameterMap().get(key)) {
-                if (idx > 0) {
-                    out.write("&".getBytes(UTF_8));
-                }
-                idx++;
-                out.write(value.getBytes(UTF_8));
-            }
+            data.put(key, request.getParameter(key));
         }
-        ByteStreams.copy(request.getInputStream(), out);
+        for (final String key : form.keySet()) {
+            data.put(key, form.getFirst(key));
+        }
+        appendFormParametersToBody(out, data);
 
+        ByteStreams.copy(request.getInputStream(), out);
         return new ByteArrayInputStream(out.toByteArray());
     }
 
+    private void appendFormParametersToBody(final ByteArrayOutputStream out, final Map<String, String> data) throws IOException {
+        int idx = 0;
+        for (final String key : data.keySet()) {
+            if (idx > 0) {
+                out.write("&".getBytes(UTF_8));
+            }
+
+            out.write((key + "=" + URLEncoder.encode(data.get(key), UTF_8_STRING)).getBytes(UTF_8));
+            idx++;
+        }
+    }
+
     private void prepareOSGIRequest(final HttpServletRequest request, final ServletContext servletContext, final ServletConfig servletConfig) {
         request.setAttribute("killbill.osgi.servletContext", servletContext);
         request.setAttribute("killbill.osgi.servletConfig", servletConfig);