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


The following commit(s) were added to refs/heads/master by this push:
     new 37230e4  [SCB-936] encode slash in path param
37230e4 is described below

commit 37230e4f06772b066750169c291f04408c4e88ca
Author: yhs0092 <[email protected]>
AuthorDate: Fri Sep 28 15:57:04 2018 +0800

    [SCB-936] encode slash in path param
---
 .../rest/definition/path/PathVarParamWriter.java   |  4 +-
 .../definition/path/PathVarParamWriterTest.java    |  9 +++
 .../foundation/common/http/HttpUtils.java          | 35 ++++++++++++
 .../foundation/common/http/TestHttpUtils.java      | 24 ++++++++
 .../it/extend/engine/ITSCBRestTemplate.java        |  9 ++-
 .../it/testcase/TestDataTypePrimitive.java         | 66 ++++++++++++++--------
 .../it/SpringBoot2ServletApplication.java          |  9 +++
 .../vertx/accesslog/AccessLogConfiguration.java    |  2 +-
 .../accesslog/AccessLogConfigurationTest.java      |  2 +-
 9 files changed, 133 insertions(+), 27 deletions(-)

diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java
index 95f4016..3cde1c0 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriter.java
@@ -21,7 +21,7 @@ import 
org.apache.servicecomb.common.rest.definition.RestParam;
 import org.apache.servicecomb.foundation.common.http.HttpUtils;
 
 /**
- * 处理动态path
+ * Dynamically processing path
  */
 public class PathVarParamWriter extends AbstractUrlParamWriter {
   public PathVarParamWriter(RestParam param) {
@@ -31,7 +31,7 @@ public class PathVarParamWriter extends 
AbstractUrlParamWriter {
   @Override
   public void write(StringBuilder builder, Object[] args) throws Exception {
     String paramValue = getParamValue(args).toString();
-    String encodedPathParam = HttpUtils.uriEncodePath(paramValue);
+    String encodedPathParam = HttpUtils.encodePathParam(paramValue);
     builder.append(encodedPathParam);
   }
 }
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java
index 664c406..dbc87f9 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/PathVarParamWriterTest.java
@@ -54,6 +54,15 @@ public class PathVarParamWriterTest {
   }
 
   @Test
+  public void writePathParamWithSlash() throws Exception {
+    PathVarParamWriter pathVarParamWriter = createPathVarParamWriter();
+    StringBuilder pathBuilder = new StringBuilder();
+    pathBuilder.append("/api/");
+    pathVarParamWriter.write(pathBuilder, new String[] {"a/bc"});
+    Assert.assertEquals("/api/a%2Fbc", pathBuilder.toString());
+  }
+
+  @Test
   public void writeIntegerParam() throws Exception {
     PathVarParamWriter pathVarParamWriter = createPathVarParamWriter();
     StringBuilder pathBuilder = new StringBuilder();
diff --git 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java
 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java
index ed94d76..0c77d19 100644
--- 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java
+++ 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/http/HttpUtils.java
@@ -22,6 +22,8 @@ import java.net.URISyntaxException;
 
 import org.springframework.util.StringUtils;
 
+import com.google.common.net.UrlEscapers;
+
 public final class HttpUtils {
   private HttpUtils() {
   }
@@ -50,6 +52,25 @@ public final class HttpUtils {
     return null;
   }
 
+  /**
+   * <pre>
+   *          foo://example.com:8042/over/there?name=ferret#nose
+   *          \_/   \______________/\_________/ \_________/ \__/
+   *           |           |            |            |        |
+   *        scheme     authority       path        query   fragment
+   *           |   _____________________|__
+   *          / \ /                        \
+   *          urn:example:animal:ferret:nose
+   * </pre>
+   * <p>the URI syntax components above is referred from <a 
href="https://tools.ietf.org/html/rfc3986#page-16";>RFC3986</a>.
+   * This method is used to encode the entire path part(e.g. /over/there in 
the example).</p>
+   * <em>In order to keep the structure of path, slash '/' will not be 
encoded. If you want to encode '/' into {@code %2F},
+   * please consider the {@link #encodePathParam(String)}
+   * </em>
+   *
+   * @param path the entire url path
+   * @return the encoded url path
+   */
   public static String uriEncodePath(String path) {
     try {
       URI uri = new URI(null, null, path, null);
@@ -59,6 +80,20 @@ public final class HttpUtils {
     }
   }
 
+  /**
+   * Encode path params. For example, if the path of an operation is {@code 
/over/there/{pathParam}/tail}, this method
+   * should be used to encoded {@code {pathParam}}. In order to keep the path 
structure, the slash '/' will be encoded
+   * into {@code %2F} to avoid path matching problem.
+   *
+   * @see UrlEscapers#urlPathSegmentEscaper()
+   *
+   * @param pathParam the path param to be encoded
+   * @return the encoded path param
+   */
+  public static String encodePathParam(String pathParam) {
+    return UrlEscapers.urlPathSegmentEscaper().escape(pathParam);
+  }
+
   public static String uriDecodePath(String path) {
     if (path == null) {
       return null;
diff --git 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java
 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java
index 98996ee..43587fc 100644
--- 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java
+++ 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/http/TestHttpUtils.java
@@ -94,6 +94,30 @@ public class TestHttpUtils {
   }
 
   @Test
+  public void uriEncode_encodeEntirePath() {
+    String encoded = HttpUtils.uriEncodePath("a%%'+b/def");
+    Assert.assertEquals("a%25%25'+b/def", encoded);
+  }
+
+  @Test
+  public void pathParamEncode() {
+    Assert.assertEquals("a+b", HttpUtils.encodePathParam("a+b"));
+    Assert.assertEquals("a%25b", HttpUtils.encodePathParam("a%b"));
+    Assert.assertEquals("a%25%25b", HttpUtils.encodePathParam("a%%b"));
+    Assert.assertEquals("%3C%20%3E'%22%EF%BC%88)&%2F%20%20", 
HttpUtils.encodePathParam("< >'\"()&/  "));
+    Assert.assertEquals("%E6%B5%8B%20%E8%AF%95", HttpUtils.encodePathParam("测 
试"));
+  }
+
+  /**
+   * SafeChar: the characters that are not encoded.
+   * This test is to show those safe chars excepting 0..9, a..z and A..Z
+   */
+  @Test
+  public void pathParamEncode_SafeChar() {
+    Assert.assertEquals("-._~!$'()*,;&=@:+", 
HttpUtils.encodePathParam("-._~!$'()*,;&=@:+"));
+  }
+
+  @Test
   public void uriDecode_failed() {
     expectedException.expect(IllegalArgumentException.class);
     expectedException
diff --git 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
index 444ffc0..9956e50 100644
--- 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
+++ 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
@@ -24,13 +24,16 @@ import 
org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 
 public class ITSCBRestTemplate extends CseRestTemplate {
+
+  private String urlPrefix;
+
   public ITSCBRestTemplate(String producerName, String schemaId) {
     MicroserviceVersionRule microserviceVersionRule = 
RegistryUtils.getServiceRegistry().getAppManager()
         .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), 
producerName,
             DefinitionConst.VERSION_RULE_ALL);
     MicroserviceVersionMeta microserviceVersionMeta = 
microserviceVersionRule.getLatestMicroserviceVersion();
     SchemaMeta schemaMeta = 
microserviceVersionMeta.getMicroserviceMeta().ensureFindSchemaMeta(schemaId);
-    String urlPrefix = String.format("cse://%s/%s", producerName, 
schemaMeta.getSwagger().getBasePath());
+    urlPrefix = String.format("cse://%s/%s", producerName, 
schemaMeta.getSwagger().getBasePath());
 
     setUriTemplateHandler(new ITUriTemplateHandler(urlPrefix));
     setRequestFactory(new ITClientHttpRequestFactory());
@@ -39,4 +42,8 @@ public class ITSCBRestTemplate extends CseRestTemplate {
   public void setTransport(String transport) {
     ((ITClientHttpRequestFactory) getRequestFactory()).setTransport(transport);
   }
+
+  public String getUrlPrefix() {
+    return urlPrefix;
+  }
 }
diff --git 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java
 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java
index da9f294..83423ce 100644
--- 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java
+++ 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDataTypePrimitive.java
@@ -18,17 +18,20 @@ package org.apache.servicecomb.it.testcase;
 
 import static org.junit.Assert.assertEquals;
 
+import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.servicecomb.it.Consumers;
+import org.apache.servicecomb.it.extend.engine.ITSCBRestTemplate;
 import org.apache.servicecomb.it.junit.ITJUnitUtils;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
+import org.springframework.web.util.UriComponentsBuilder;
 
 public class TestDataTypePrimitive {
   interface DataTypePojoIntf {
@@ -99,17 +102,15 @@ public class TestDataTypePrimitive {
 
   private static String producerName;
 
-  @Before
-  public void prepare() {
-    if (!ITJUnitUtils.getProducerName().equals(producerName)) {
-      producerName = ITJUnitUtils.getProducerName();
-      consumersPojo = new Consumers<>(producerName, "dataTypePojo", 
DataTypePojoIntf.class);
-      consumersJaxrs = new Consumers<>(producerName, "dataTypeJaxrs", 
DataTypeRestIntf.class);
-      consumersSpringmvc = new Consumers<>(producerName, "dataTypeSpringmvc", 
DataTypeRestIntf.class);
-      consumersPojo.init(ITJUnitUtils.getTransport());
-      consumersJaxrs.init(ITJUnitUtils.getTransport());
-      consumersSpringmvc.init(ITJUnitUtils.getTransport());
-    }
+  @BeforeClass
+  public static void beforeClass() {
+    producerName = ITJUnitUtils.getProducerName();
+    consumersPojo = new Consumers<>(producerName, "dataTypePojo", 
DataTypePojoIntf.class);
+    consumersJaxrs = new Consumers<>(producerName, "dataTypeJaxrs", 
DataTypeRestIntf.class);
+    consumersSpringmvc = new Consumers<>(producerName, "dataTypeSpringmvc", 
DataTypeRestIntf.class);
+    consumersPojo.init(ITJUnitUtils.getTransport());
+    consumersJaxrs.init(ITJUnitUtils.getTransport());
+    consumersSpringmvc.init(ITJUnitUtils.getTransport());
   }
 
   @Test
@@ -204,7 +205,7 @@ public class TestDataTypePrimitive {
 
   @Test
   public void stringPath_jaxrs_intf() {
-    String expect = "serviceComb";
+    String expect = "serviceComb/serviceComb";
     assertEquals(expect, consumersJaxrs.getIntf().stringPath(expect));
   }
 
@@ -227,6 +228,19 @@ public class TestDataTypePrimitive {
   }
 
   @Test
+  public void stringPath_jaxrs_rt_with_encoded_slash() {
+    String requestPathParam = "serviceComb%2FserviceComb";
+    String expectResponse = "serviceComb/serviceComb";
+    // build request uri to avoid Spring's encoding path
+    URI requestUri = UriComponentsBuilder
+        .fromUriString(((ITSCBRestTemplate) 
consumersJaxrs.getSCBRestTemplate()).getUrlPrefix()
+            + "/stringPath/" + requestPathParam)
+        .build(true).toUri();
+    assertEquals(expectResponse,
+        consumersJaxrs.getSCBRestTemplate().getForObject(requestUri, 
String.class));
+  }
+
+  @Test
   public void intQuery_jaxrs_intf() {
     assertEquals(10, consumersJaxrs.getIntf().intQuery(10));
   }
@@ -290,8 +304,7 @@ public class TestDataTypePrimitive {
     HttpHeaders headers = new HttpHeaders();
     headers.add("input", "10");
 
-    @SuppressWarnings("rawtypes")
-    HttpEntity entity = new HttpEntity<>(null, headers);
+    HttpEntity<?> entity = new HttpEntity<>(null, headers);
     ResponseEntity<Integer> response = consumers.getSCBRestTemplate()
         .exchange("/intHeader",
             HttpMethod.GET,
@@ -324,8 +337,7 @@ public class TestDataTypePrimitive {
     HttpHeaders headers = new HttpHeaders();
     headers.add("input", expect);
 
-    @SuppressWarnings("rawtypes")
-    HttpEntity entity = new HttpEntity<>(null, headers);
+    HttpEntity<?> entity = new HttpEntity<>(null, headers);
     ResponseEntity<String> response = consumers.getSCBRestTemplate()
         .exchange("/stringHeader",
             HttpMethod.GET,
@@ -364,8 +376,7 @@ public class TestDataTypePrimitive {
     HttpHeaders headers = new HttpHeaders();
     headers.add("Cookie", "input=10");
 
-    @SuppressWarnings("rawtypes")
-    HttpEntity entity = new HttpEntity<>(null, headers);
+    HttpEntity<?> entity = new HttpEntity<>(null, headers);
     ResponseEntity<Integer> response = consumers.getSCBRestTemplate()
         .exchange("/intCookie",
             HttpMethod.GET,
@@ -398,8 +409,7 @@ public class TestDataTypePrimitive {
     HttpHeaders headers = new HttpHeaders();
     headers.add("Cookie", "input=" + expect);
 
-    @SuppressWarnings("rawtypes")
-    HttpEntity entity = new HttpEntity<>(null, headers);
+    HttpEntity<?> entity = new HttpEntity<>(null, headers);
     ResponseEntity<String> response = consumers.getSCBRestTemplate()
         .exchange("/stringCookie",
             HttpMethod.GET,
@@ -546,7 +556,7 @@ public class TestDataTypePrimitive {
 
   @Test
   public void stringPath_springmvc_intf() {
-    String expect = "serviceComb";
+    String expect = "serviceComb/serviceComb";
     assertEquals(expect, consumersSpringmvc.getIntf().stringPath(expect));
   }
 
@@ -569,6 +579,18 @@ public class TestDataTypePrimitive {
   }
 
   @Test
+  public void stringPath_springmvc_rt_with_encoded_slash() {
+    String requestPathParam = "serviceComb%2FserviceComb";
+    String expectResponse = "serviceComb/serviceComb";
+    URI requestUri = UriComponentsBuilder
+        .fromUriString(((ITSCBRestTemplate) 
consumersSpringmvc.getSCBRestTemplate()).getUrlPrefix()
+            + "/stringPath/" + requestPathParam)
+        .build(true).toUri();
+    assertEquals(expectResponse,
+        consumersSpringmvc.getSCBRestTemplate().getForObject(requestUri, 
String.class));
+  }
+
+  @Test
   public void intQuery_springmvc_intf() {
     assertEquals(10, consumersSpringmvc.getIntf().intQuery(10));
   }
diff --git 
a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java
 
b/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java
index 87236e3..6b19ad8 100644
--- 
a/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java
+++ 
b/integration-tests/it-producer-deploy-springboot2-servlet/src/main/java/org/apache/servicecomb/it/SpringBoot2ServletApplication.java
@@ -24,9 +24,18 @@ import 
org.springframework.boot.autoconfigure.SpringBootApplication;
 @SpringBootApplication
 @EnableServiceComb
 public class SpringBoot2ServletApplication {
+
+  /**
+   * Allow encoded slash in path param(%2F).
+   * This property is set for {@code stringPath} tests in {@code 
TestDataTypePrimitive}
+   */
+  private static final String TOMCAT_ALLOW_ENCODED_SLASH = 
"org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH";
+
   public static void main(String[] args) {
     new CommandReceiver();
 
+    System.setProperty(TOMCAT_ALLOW_ENCODED_SLASH, "true");
     SpringApplication.run(SpringBoot2ServletApplication.class, args);
+    System.clearProperty(TOMCAT_ALLOW_ENCODED_SLASH);
   }
 }
diff --git 
a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
 
b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
index 6f10955..eee4307 100644
--- 
a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
+++ 
b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfiguration.java
@@ -29,7 +29,7 @@ public final class AccessLogConfiguration {
 
   public static final AccessLogConfiguration INSTANCE = new 
AccessLogConfiguration();
 
-  public static final String DEFAULT_PATTERN = "%h - - %t %r %s %B";
+  public static final String DEFAULT_PATTERN = "%h - - %t %r %s %B %D";
 
   private AccessLogConfiguration() {
 
diff --git 
a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
 
b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
index e4ae886..0dd1af6 100644
--- 
a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
+++ 
b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/accesslog/AccessLogConfigurationTest.java
@@ -33,6 +33,6 @@ public class AccessLogConfigurationTest {
   @Test
   public void getAccesslogPattern() {
     String result = AccessLogConfiguration.INSTANCE.getAccesslogPattern();
-    assertEquals("%h - - %t %r %s %B", result);
+    assertEquals("%h - - %t %r %s %B %D", result);
   }
 }

Reply via email to