You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by aw...@apache.org on 2009/04/08 06:53:42 UTC

svn commit: r763104 - in /incubator/shindig/trunk/java/common/src: main/java/org/apache/shindig/protocol/JsonRpcServlet.java test/java/org/apache/shindig/protocol/JsonRpcServletTest.java

Author: awiner
Date: Wed Apr  8 04:53:41 2009
New Revision: 763104

URL: http://svn.apache.org/viewvc?rev=763104&view=rev
Log:
SHINDIG-1009: content-type check should only be perfomed on "request" field of multipart/form-data
- Patch from Sachin Shenoy, with some minor changes to the test

Modified:
    incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java
    incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java

Modified: incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java?rev=763104&r1=763103&r2=763104&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java (original)
+++ incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/JsonRpcServlet.java Wed Apr  8 04:53:41 2009
@@ -101,13 +101,12 @@
 
       if (formParser.isMultipartContent(servletRequest)) {
         for (FormDataItem item : formParser.parse(servletRequest)) {
-          if (item.isFormField() && content == null) {
+          if (item.isFormField() && REQUEST_PARAM.equals(item.getFieldName()) && content == null) {
             // As per spec, in case of a multipart/form-data content, there will be one form field
             // with field name as "request". It will contain the json request. Any further form
             // field or file item will not be parsed out, but will be exposed via getFormItem
-            // method of RequestItem. Here we are lenient where a mime part which has content type
-            // application/json will be considered as request.
-            if (!REQUEST_PARAM.equals(item.getFieldName())) {
+            // method of RequestItem.
+            if (!StringUtils.isEmpty(item.getContentType())) {
               checkContentTypes(ContentTypes.ALLOWED_JSON_CONTENT_TYPES, item.getContentType());
             }
             content = IOUtils.toString(item.getInputStream());

Modified: incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java?rev=763104&r1=763103&r2=763104&view=diff
==============================================================================
--- incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java (original)
+++ incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java Wed Apr  8 04:53:41 2009
@@ -17,29 +17,24 @@
  */
 package org.apache.shindig.protocol;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.inject.Guice;
-
-import junit.framework.TestCase;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.classextension.EasyMock.reset;
 
 import org.apache.shindig.common.JsonAssert;
 import org.apache.shindig.common.testing.FakeGadgetToken;
 import org.apache.shindig.protocol.conversion.BeanJsonConverter;
 import org.apache.shindig.protocol.multipart.FormDataItem;
 import org.apache.shindig.protocol.multipart.MultipartFormParser;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
 import org.easymock.IMocksControl;
 import org.easymock.classextension.EasyMock;
-import static org.easymock.classextension.EasyMock.reset;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -47,6 +42,12 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import junit.framework.TestCase;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+
 /**
  *
  */
@@ -56,7 +57,8 @@
       .setOwnerId("john.doe").setViewerId("john.doe");
 
   private static final String IMAGE_FIELDNAME = "profile-photo";
-  private static final byte[] IMAGE_DATA = "image data".getBytes();
+  private static final String IMAGE_DATA = "image data";
+  private static final byte[] IMAGE_DATA_BYTES = IMAGE_DATA.getBytes();
   private static final String IMAGE_TYPE = "image/jpeg";
 
   private HttpServletRequest req;
@@ -132,12 +134,12 @@
     res.setCharacterEncoding("UTF-8");
     res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
 
-    List<FormDataItem> formItems = new ArrayList<FormDataItem>();
-    String request = "{method:test.get,id:id,params:" +
-        "{userId:5,groupId:@self,image-ref:@" + IMAGE_FIELDNAME + "}}";
+    List<FormDataItem> formItems = Lists.newArrayList();
+    String request = "{method:'test.get',id:'id',params:" +
+        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
     formItems.add(mockFormDataItem(JsonRpcServlet.REQUEST_PARAM,
         ContentTypes.OUTPUT_JSON_CONTENT_TYPE, request.getBytes(), true));
-    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA, false));
+    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
     expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
     expect(multipartFormParser.parse(req)).andReturn(formItems);
     expect(res.getWriter()).andReturn(writer);
@@ -147,15 +149,15 @@
     servlet.service(req, res);
     mockControl.verify();
 
-    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new String(IMAGE_DATA) +
+    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
         "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
   }
 
   /**
-   * Tests whether mime part with content type appliction/json is picked up as
-   * request even when its fieldname is not "request".
+   * Test that it passes even when content-type is not set for "request" parameter. This would
+   * be the case where the request is published via webform.
    */
-  public void testPostMultipartFormDataWithNoExplicitRequestField() throws Exception {
+  public void testPostMultipartFormDataWithRequestFieldHavingNoContentType() throws Exception {
     reset(multipartFormParser);
 
     handler.setMock(new TestHandler() {
@@ -174,12 +176,11 @@
     res.setCharacterEncoding("UTF-8");
     res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
 
-    List<FormDataItem> formItems = new ArrayList<FormDataItem>();
-    String request = "{method:test.get,id:id,params:" +
-        "{userId:5,groupId:@self,image-ref:@" + IMAGE_FIELDNAME + "}}";
-    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA, false));
-    formItems.add(mockFormDataItem("json", ContentTypes.OUTPUT_JSON_CONTENT_TYPE,
-        request.getBytes(), true));
+    List<FormDataItem> formItems = Lists.newArrayList();
+    String request = "{method:'test.get',id:'id',params:" +
+        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
+    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
+    formItems.add(mockFormDataItem("request", null, request.getBytes(), true));
     expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
     expect(multipartFormParser.parse(req)).andReturn(formItems);
     expect(res.getWriter()).andReturn(writer);
@@ -189,11 +190,99 @@
     servlet.service(req, res);
     mockControl.verify();
 
-    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new String(IMAGE_DATA) +
+    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
         "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
   }
 
 
+  /**
+   * Test that any form-data other than "request" does not undergo any content type check.
+   */
+  public void testPostMultipartFormDataOnlyRequestFieldHasContentTypeChecked()
+      throws Exception {
+    reset(multipartFormParser);
+
+    handler.setMock(new TestHandler() {
+      @Override
+      public Object get(RequestItem req) {
+        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
+        return ImmutableMap.of("image-data", new String(item.get()),
+            "image-type", item.getContentType(),
+            "image-ref", req.getParameter("image-ref"));
+      }
+    });
+    expect(req.getMethod()).andStubReturn("POST");
+    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
+    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
+    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
+    res.setCharacterEncoding("UTF-8");
+    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
+
+    List<FormDataItem> formItems = Lists.newArrayList();
+    String request = "{method:'test.get',id:'id',params:" +
+        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
+    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
+    formItems.add(mockFormDataItem("oauth_hash", "application/octet-stream",
+        "oauth-hash".getBytes(), true));
+    formItems.add(mockFormDataItem("request", null, request.getBytes(), true));
+    formItems.add(mockFormDataItem("oauth_signature", "application/octet-stream",
+        "oauth_signature".getBytes(), true));
+    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
+    expect(multipartFormParser.parse(req)).andReturn(formItems);
+    expect(res.getWriter()).andReturn(writer);
+    expectLastCall();
+
+    mockControl.replay();
+    servlet.service(req, res);
+    mockControl.verify();
+
+    JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + IMAGE_DATA +
+        "', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME + "'}}", getOutput());
+  }
+
+  /**
+   * Test that "request" field undergoes contentType check, and error is thrown if wrong content
+   * type is present. 
+   */
+  public void testPostMultipartFormDataRequestFieldIsSubjectedToContentTypeCheck()
+      throws Exception {
+    reset(multipartFormParser);
+
+    handler.setMock(new TestHandler() {
+      @Override
+      public Object get(RequestItem req) {
+        FormDataItem item = req.getFormMimePart(IMAGE_FIELDNAME);
+        return ImmutableMap.of("image-data", item.get(),
+            "image-type", item.getContentType(),
+            "image-ref", req.getParameter("image-ref"));
+      }
+    });
+    expect(req.getMethod()).andStubReturn("POST");
+    expect(req.getAttribute(isA(String.class))).andReturn(FAKE_GADGET_TOKEN);
+    expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
+    expect(req.getContentType()).andStubReturn(ContentTypes.MULTIPART_FORM_CONTENT_TYPE);
+    res.setCharacterEncoding("UTF-8");
+    res.setContentType(ContentTypes.OUTPUT_JSON_CONTENT_TYPE);
+
+    List<FormDataItem> formItems = Lists.newArrayList();
+    String request = "{method:'test.get',id:'id',params:" +
+        "{userId:5,groupId:'@self',image-ref:'@" + IMAGE_FIELDNAME + "'}}";
+    formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA_BYTES, false));
+    formItems.add(mockFormDataItem("request", "application/octet-stream", request.getBytes(),
+        true));
+    expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
+    expect(multipartFormParser.parse(req)).andReturn(formItems);
+    expect(res.getWriter()).andReturn(writer);
+    expectLastCall();
+
+    mockControl.replay();
+    servlet.service(req, res);
+    mockControl.verify();
+
+    String output = getOutput();
+    assertTrue(-1 != output.indexOf("Unsupported Content-Type application/octet-stream"));
+  }
+
   public void testInvalidService() throws Exception {
     setupRequest("{method:junk.get,id:id,params:{userId:5,groupId:@self}}");