You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/06/04 06:22:17 UTC

[incubator-servicecomb-java-chassis] 01/03: [SCB-637] StandardHttpServletRequestEx parse application/x-www-form-urlencoded even not post request (servlet 3.1 defined only parsed for post request)

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit eca457968972d2636ec5e359f61bace800c160b5
Author: wujimin <wu...@huawei.com>
AuthorDate: Mon Jun 4 00:09:58 2018 +0800

    [SCB-637] StandardHttpServletRequestEx parse application/x-www-form-urlencoded even not post request (servlet 3.1 defined only parsed for post request)
---
 .../vertx/http/StandardHttpServletRequestEx.java   | 90 ++++++++++++++++++++++
 .../http/TestStandardHttpServletRequestEx.java     | 54 +++++++++++++
 2 files changed, 144 insertions(+)

diff --git a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java
index a6b142d..f9b29ca 100644
--- a/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java
+++ b/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/StandardHttpServletRequestEx.java
@@ -18,12 +18,27 @@
 package org.apache.servicecomb.foundation.vertx.http;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MediaType;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream;
 
 import io.netty.buffer.ByteBuf;
@@ -37,6 +52,11 @@ public class StandardHttpServletRequestEx extends HttpServletRequestWrapper impl
 
   private ServletInputStream inputStream;
 
+  // by servlet specification
+  // only parse application/x-www-form-urlencoded of post request automatically
+  // we will parse this even not post method
+  private Map<String, String[]> parameterMap;
+
   public StandardHttpServletRequestEx(HttpServletRequest request) {
     super(request);
   }
@@ -79,4 +99,74 @@ public class StandardHttpServletRequestEx extends HttpServletRequestWrapper impl
   public int getBodyBytesLength() {
     return bodyBuffer.getBodyBytesLength();
   }
+
+  private Map<String, String[]> parseParameterMap() {
+    // 1.post method already parsed by servlet
+    // 2.not APPLICATION_FORM_URLENCODED, no need to enhance
+    if (getMethod().equalsIgnoreCase(HttpMethod.POST)
+        || !StringUtils.startsWithIgnoreCase(getContentType(), MediaType.APPLICATION_FORM_URLENCODED)) {
+      return super.getParameterMap();
+    }
+
+    Map<String, List<String>> listMap = parseUrlEncodedBody();
+    mergeParameterMaptoListMap(listMap);
+    return convertListMapToArrayMap(listMap);
+  }
+
+  private Map<String, String[]> convertListMapToArrayMap(Map<String, List<String>> listMap) {
+    Map<String, String[]> arrayMap = new HashMap<>();
+    for (Entry<String, List<String>> entry : listMap.entrySet()) {
+      arrayMap.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
+    }
+    return arrayMap;
+  }
+
+  private void mergeParameterMaptoListMap(Map<String, List<String>> listMap) {
+    for (Entry<String, String[]> entry : super.getParameterMap().entrySet()) {
+      List<String> values = listMap.computeIfAbsent(entry.getKey(), k -> new ArrayList<>());
+      // follow servlet behavior, inherited value first, and then body value
+      values.addAll(0, Arrays.asList(entry.getValue()));
+    }
+  }
+
+  private Map<String, List<String>> parseUrlEncodedBody() {
+    try (InputStream inputStream = getInputStream()) {
+      Map<String, List<String>> listMap = new HashMap<>();
+      String body = IOUtils.toString(inputStream);
+      List<NameValuePair> pairs = URLEncodedUtils
+          .parse(body, getCharacterEncoding() == null ? null : Charset.forName(getCharacterEncoding()));
+      for (NameValuePair pair : pairs) {
+        List<String> values = listMap.computeIfAbsent(pair.getName(), k -> new ArrayList<>());
+        values.add(pair.getValue());
+      }
+      return listMap;
+    } catch (IOException e) {
+      throw new IllegalStateException("", e);
+    }
+  }
+
+  @Override
+  public String[] getParameterValues(String name) {
+    return getParameterMap().get(name);
+  }
+
+  @Override
+  public String getParameter(String name) {
+    String[] values = getParameterMap().get(name);
+    return values == null ? null : values[0];
+  }
+
+  @Override
+  public Enumeration<String> getParameterNames() {
+    return Collections.enumeration(getParameterMap().keySet());
+  }
+
+  @Override
+  public Map<String, String[]> getParameterMap() {
+    if (parameterMap == null) {
+      parameterMap = parseParameterMap();
+    }
+
+    return parameterMap;
+  }
 }
diff --git a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java
index ed5a884..f87e83c 100644
--- a/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java
+++ b/foundations/foundation-vertx/src/test/java/org/apache/servicecomb/foundation/vertx/http/TestStandardHttpServletRequestEx.java
@@ -19,11 +19,19 @@ package org.apache.servicecomb.foundation.vertx.http;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
 
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MediaType;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream;
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -78,4 +86,50 @@ public class TestStandardHttpServletRequestEx {
     // do not create another one
     Assert.assertSame(cachedInputStream, requestEx.getInputStream());
   }
+
+  @Test
+  public void parameterMap_inherited() {
+    Map<String, String[]> inherited = new HashMap<>();
+    String[] v1 = new String[] {"v1-1", "v1-2"};
+    inherited.put("p1", v1);
+    new Expectations() {
+      {
+        request.getParameterMap();
+        result = inherited;
+        request.getMethod();
+        result = HttpMethod.POST;
+      }
+    };
+
+    Assert.assertSame(inherited, requestEx.getParameterMap());
+    Assert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("p1"));
+    Assert.assertSame(v1, requestEx.getParameterValues("p1"));
+    Assert.assertEquals("v1-1", requestEx.getParameter("p1"));
+  }
+
+  @Test
+  public void parameterMap_merge() throws IOException {
+    Map<String, String[]> inherited = new HashMap<>();
+    String[] v1 = new String[] {"v1-1", "v1-2"};
+    inherited.put("p1", v1);
+
+    Buffer buffer = Buffer.buffer("p1=v1-3;p2=v2");
+    BufferInputStream inputStream = new BufferInputStream(buffer.getByteBuf());
+    new Expectations() {
+      {
+        request.getParameterMap();
+        result = inherited;
+        request.getMethod();
+        result = HttpMethod.PUT;
+        request.getContentType();
+        result = MediaType.APPLICATION_FORM_URLENCODED.toUpperCase(Locale.US) + ";abc";
+        request.getInputStream();
+        result = inputStream;
+      }
+    };
+
+    Assert.assertThat(Collections.list(requestEx.getParameterNames()), Matchers.contains("p1", "p2"));
+    Assert.assertThat(requestEx.getParameterValues("p1"), Matchers.arrayContaining("v1-1", "v1-2", "v1-3"));
+    Assert.assertEquals("v1-1", requestEx.getParameter("p1"));
+  }
 }

-- 
To stop receiving notification emails like this one, please contact
liubao@apache.org.