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 2020/12/04 09:22:58 UTC
[servicecomb-java-chassis] branch master updated: [SCB-2142] add
RestClientEncoder (#2101)
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/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/master by this push:
new 71c0cba [SCB-2142] add RestClientEncoder (#2101)
71c0cba is described below
commit 71c0cbab8f2c78cd8a5dcc7d9aa870a3cdced476
Author: wujimin <wu...@huawei.com>
AuthorDate: Fri Dec 4 17:22:48 2020 +0800
[SCB-2142] add RestClientEncoder (#2101)
---
.../transport/rest/client/RestClientEncoder.java | 233 +++++++++++++++++++++
.../rest/client/RestClientExceptionCodes.java | 1 +
...atureController.java => FakeRestTransport.java} | 32 ++-
.../rest/client/RestClientEncoderTest.java | 185 ++++++++++++++++
...extFactoryTest.java => RestClientTestBase.java} | 110 ++--------
.../RestClientTransportContextFactoryTest.java | 135 +++---------
.../rest/client/RestFeatureController.java | 43 ++++
7 files changed, 538 insertions(+), 201 deletions(-)
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java
new file mode 100644
index 0000000..fa36b4f
--- /dev/null
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.transport.rest.client;
+
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA;
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+import static org.apache.servicecomb.transport.rest.client.RestClientExceptionCodes.FAILED_TO_ENCODE_REST_CLIENT_REQUEST;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.servlet.http.Part;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.servicecomb.common.rest.codec.RestCodec;
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.common.rest.codec.query.QueryCodec;
+import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.definition.OperationConfig;
+import org.apache.servicecomb.foundation.common.utils.StringBuilderUtils;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpClientRequest;
+
+/**
+ * encode all send data except upload
+ */
+public class RestClientEncoder {
+ private static final Logger LOGGER = LoggerFactory.getLogger(RestClientEncoder.class);
+
+ public static final int FORM_BUFFER_SIZE = 1024;
+
+ protected final Invocation invocation;
+
+ protected final RestClientTransportContext transportContext;
+
+ protected final RestClientRequestParameters requestParameters;
+
+ protected final HttpClientRequest httpClientRequest;
+
+ public RestClientEncoder(Invocation invocation) {
+ this.invocation = invocation;
+ this.transportContext = invocation.getTransportContext();
+ this.requestParameters = transportContext.getRequestParameters();
+ this.httpClientRequest = transportContext.getHttpClientRequest();
+ }
+
+ public void encode() {
+ try {
+ doEncode();
+ } catch (Exception e) {
+ throw new InvocationException(BAD_REQUEST, FAILED_TO_ENCODE_REST_CLIENT_REQUEST, e.getMessage(), e);
+ }
+ }
+
+ protected void doEncode() throws Exception {
+ LOGGER.debug("rest client request, method={}, operation={}, endpoint={}, path={}.",
+ httpClientRequest.method(),
+ invocation.getMicroserviceQualifiedName(),
+ invocation.getEndpoint().getEndpoint(),
+ httpClientRequest.uri());
+
+ swaggerArgumentsToRequest();
+
+ writeCookies(requestParameters.getCookieMap());
+ writeScbHeaders();
+ writeForm(requestParameters.getFormMap());
+ }
+
+ protected void swaggerArgumentsToRequest() throws Exception {
+ RestCodec.argsToRest(invocation.getSwaggerArguments(), transportContext.getRestOperationMeta(), requestParameters);
+ }
+
+ protected void writeCookies(@Nullable Map<String, String> cookieMap) {
+ if (CollectionUtils.isEmpty(cookieMap)) {
+ return;
+ }
+
+ StringBuilder builder = new StringBuilder();
+ for (Entry<String, String> entry : cookieMap.entrySet()) {
+ builder.append(entry.getKey())
+ .append('=')
+ .append(entry.getValue())
+ .append("; ");
+ }
+ StringBuilderUtils.deleteLast(builder, 2);
+ httpClientRequest.putHeader(HttpHeaders.COOKIE, builder.toString());
+ }
+
+ protected void writeScbHeaders() throws JsonProcessingException {
+ OperationConfig operationConfig = invocation.getOperationMeta().getConfig();
+ if (invocation.isThirdPartyInvocation() && operationConfig.isClientRequestHeaderFilterEnabled()) {
+ return;
+ }
+
+ httpClientRequest.putHeader(Const.TARGET_MICROSERVICE, invocation.getMicroserviceName());
+ httpClientRequest.putHeader(Const.CSE_CONTEXT,
+ RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(invocation.getContext()));
+ }
+
+ protected void writeForm(@Nullable Map<String, Object> formMap) throws Exception {
+ if (requestParameters.getUploads() == null) {
+ writeUrlEncodedForm(formMap);
+ return;
+ }
+
+ writeChunkedForm(formMap);
+ }
+
+ protected void writeUrlEncodedForm(@Nullable Map<String, Object> formMap) throws Exception {
+ if (formMap == null) {
+ return;
+ }
+
+ httpClientRequest.putHeader(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
+
+ Buffer bodyBuffer = genUrlEncodedFormBuffer(formMap);
+ requestParameters.setBodyBuffer(bodyBuffer);
+ }
+
+ protected Buffer genUrlEncodedFormBuffer(@Nonnull Map<String, Object> formMap) throws Exception {
+ // 2x faster than UriComponentsBuilder
+ ByteBuf byteBuf = Unpooled.buffer(FORM_BUFFER_SIZE);
+ for (Entry<String, Object> entry : formMap.entrySet()) {
+ writeCharSequence(byteBuf, entry.getKey());
+ byteBuf.writeByte('=');
+
+ String value = QueryCodec.convertToString(entry.getValue());
+ String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
+ writeCharSequence(byteBuf, encodedValue);
+
+ byteBuf.markWriterIndex();
+ byteBuf.writeByte('&');
+ }
+
+ byteBuf.resetWriterIndex();
+ return Buffer.buffer(byteBuf);
+ }
+
+ protected void writeChunkedForm(@Nullable Map<String, Object> formMap) throws Exception {
+ String boundary = transportContext.getOrCreateBoundary();
+
+ httpClientRequest.setChunked(true);
+ httpClientRequest.putHeader(CONTENT_TYPE, MULTIPART_FORM_DATA + "; charset=UTF-8; boundary=" + boundary);
+
+ if (formMap == null) {
+ return;
+ }
+
+ Buffer bodyBuffer = genChunkedFormBuffer(formMap, boundary);
+ requestParameters.setBodyBuffer(bodyBuffer);
+ }
+
+ protected Buffer genChunkedFormBuffer(@Nonnull Map<String, Object> formMap, String boundary) throws Exception {
+ ByteBuf byteBuf = Unpooled.buffer(FORM_BUFFER_SIZE);
+ for (Entry<String, Object> entry : formMap.entrySet()) {
+ writeCharSequence(byteBuf, "\r\n--");
+ writeCharSequence(byteBuf, boundary);
+ writeCharSequence(byteBuf, "\r\nContent-Disposition: form-data; name=\"");
+ writeCharSequence(byteBuf, entry.getKey());
+ writeCharSequence(byteBuf, "\"\r\n\r\n");
+
+ String value = QueryCodec.convertToString(entry.getValue());
+ writeCharSequence(byteBuf, value);
+ }
+ return Buffer.buffer(byteBuf);
+ }
+
+ protected static void writeCharSequence(ByteBuf byteBuf, String value) {
+ byteBuf.writeCharSequence(value, StandardCharsets.UTF_8);
+ }
+
+ public static Buffer genFileBoundaryBuffer(Part part, String name, String boundary) {
+ ByteBuf byteBuf = Unpooled.buffer();
+
+ writeCharSequence(byteBuf, "\r\n--");
+ writeCharSequence(byteBuf, boundary);
+ writeCharSequence(byteBuf, "\r\nContent-Disposition: form-data; name=\"");
+ writeCharSequence(byteBuf, name);
+ writeCharSequence(byteBuf, "\" filename=\"");
+ writeCharSequence(byteBuf, String.valueOf(part.getSubmittedFileName()));
+ writeCharSequence(byteBuf, "\"\r\n");
+
+ writeCharSequence(byteBuf, "Content-Type: ");
+ writeCharSequence(byteBuf, part.getContentType());
+ writeCharSequence(byteBuf, "\r\n");
+
+ writeCharSequence(byteBuf, "Content-Transfer-Encoding: binary\r\n");
+
+ writeCharSequence(byteBuf, "\r\n");
+
+ return Buffer.buffer(byteBuf);
+ }
+
+ public static Buffer genBoundaryEndBuffer(String boundary) {
+ ByteBuf byteBuf = Unpooled.buffer();
+
+ writeCharSequence(byteBuf, "\r\n--");
+ writeCharSequence(byteBuf, boundary);
+ writeCharSequence(byteBuf, "--\r\n");
+
+ return Buffer.buffer(byteBuf);
+ }
+}
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
index c30010f..5dcef13 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientExceptionCodes.java
@@ -18,4 +18,5 @@ package org.apache.servicecomb.transport.rest.client;
public interface RestClientExceptionCodes {
String FAILED_TO_CREATE_REST_CLIENT_TRANSPORT_CONTEXT = "scb_rest_client.40000000";
+ String FAILED_TO_ENCODE_REST_CLIENT_REQUEST = "scb_rest_client.40000001";
}
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java
similarity index 58%
copy from transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
copy to transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java
index a11f10f..17e1d86 100644
--- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/FakeRestTransport.java
@@ -16,17 +16,29 @@
*/
package org.apache.servicecomb.transport.rest.client;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.QueryParam;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.transport.AbstractTransport;
+import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
-@Path("/")
-public class RestFeatureController {
- public static final String SCHEMA_ID = "rest-feature";
+class FakeRestTransport extends AbstractTransport {
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public boolean init() {
+ return false;
+ }
+
+ @Override
+ public void send(Invocation invocation, AsyncResponse asyncResp) {
+
+ }
- @GET
- @Path("/query")
- public String query(@QueryParam("query") String query) {
- return query;
+ @Override
+ public Object parseAddress(String address) {
+ return new URIEndpointObject(address);
}
}
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java
new file mode 100644
index 0000000..753220f
--- /dev/null
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.transport.rest.client;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.Part;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.servicecomb.foundation.common.part.FilePart;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+class RestClientEncoderTest extends RestClientTestBase {
+ RestClientEncoder encoder;
+
+ void init(String operationId, Map<String, Object> swaggerArgs) {
+ init(operationId, swaggerArgs, false);
+ encoder = new RestClientEncoder(invocation);
+ }
+
+ @Test
+ void should_encode_header_parameter() {
+ init("header", ImmutableMap.of("header", "value"));
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().get("header"))
+ .isEqualTo("value");
+ }
+
+ @Test
+ void should_encode_servicecomb_headers() {
+ init("header", ImmutableMap.of("header", "value"));
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().toString())
+ .isEqualTo("header: value\n"
+ + "x-cse-target-microservice: defaultMicroservice\n"
+ + "x-cse-context: {\"x-cse-src-microservice\":\"defaultMicroservice\"}\n");
+ }
+
+ @Test
+ void should_not_encode_servicecomb_headers_when_invoke_3rd_service_and_filter_servicecomb_headers() {
+ init("header", ImmutableMap.of("header", "value"));
+ referenceConfig.setThirdPartyService(true);
+ operationMeta.getConfig().setClientRequestHeaderFilterEnabled(true);
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().toString())
+ .isEqualTo("header: value\n");
+ }
+
+ @Test
+ void should_encode_servicecomb_headers_when_invoke_3rd_service_and_not_filter_servicecomb_headers() {
+ init("header", ImmutableMap.of("header", "value"));
+ referenceConfig.setThirdPartyService(true);
+ operationMeta.getConfig().setClientRequestHeaderFilterEnabled(false);
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().toString())
+ .isEqualTo("header: value\n"
+ + "x-cse-target-microservice: defaultMicroservice\n"
+ + "x-cse-context: {\"x-cse-src-microservice\":\"defaultMicroservice\"}\n");
+ }
+
+ @Test
+ void should_encode_cookie_parameter() {
+ init("cookie", ImmutableMap.of("cookie1", "v1", "cookie2", "v2"));
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().get(HttpHeaders.COOKIE))
+ .isEqualTo("cookie1=v1; cookie2=v2");
+ }
+
+ @Test
+ void should_encode_body_parameter() {
+ init("body", ImmutableMap.of("body", "value"));
+
+ encoder.encode();
+
+ assertThat(transportContext.getRequestParameters().getBodyBuffer().toString())
+ .isEqualTo("\"value\"");
+ }
+
+ @Test
+ void should_encode_form_attribute_parameter() {
+ init("form", ImmutableMap.of("form1", "v1", "form2", "v2"));
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().get(HttpHeaders.CONTENT_TYPE))
+ .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
+ assertThat(transportContext.getRequestParameters().getBodyBuffer().toString())
+ .isEqualTo("form1=v1&form2=v2");
+ }
+
+ @Test
+ void should_not_encode_null_form_attribute() {
+ Map<String, Object> swaggerArgs = new HashMap<>();
+ swaggerArgs.put("form1", "v1");
+ swaggerArgs.put("form2", null);
+ init("form", swaggerArgs);
+
+ encoder.encode();
+
+ assertThat(httpClientRequest.headers().get(HttpHeaders.CONTENT_TYPE))
+ .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
+ assertThat(transportContext.getRequestParameters().getBodyBuffer().toString())
+ .isEqualTo("form1=v1");
+ }
+
+ @Test
+ void should_encode_form_with_upload_parameter() {
+ init("formWithUpload", ImmutableMap.of("form1", "v1", "form2", new File("form2")));
+
+ encoder.encode();
+
+ RestClientRequestParameters requestParameters = transportContext.getRequestParameters();
+ assertThat(requestParameters.getBodyBuffer().toString())
+ .isEqualTo("\r\n"
+ + "--my-boundary\r\n"
+ + "Content-Disposition: form-data; name=\"form1\"\r\n"
+ + "\r\n"
+ + "v1");
+ List<Part> parts = Lists.newArrayList(requestParameters.getUploads().get("form2"));
+ assertThat(parts).hasSize(1);
+ assertThat(((FilePart) parts.get(0))).isInstanceOf(FilePart.class);
+ }
+
+ @Test
+ void should_encode_form_with_upload_list() {
+ init("formWithUploadList", ImmutableMap.of("files", Arrays.asList(new File("f1"), new File("f2"))));
+
+ encoder.encode();
+
+ checkUploadList();
+ }
+
+ @Test
+ void should_encode_form_with_upload_array() {
+ init("formWithUploadList", ImmutableMap.of("files", new File[] {new File("f1"), new File("f2")}));
+
+ encoder.encode();
+
+ checkUploadList();
+ }
+
+ private void checkUploadList() {
+ RestClientRequestParameters requestParameters = transportContext.getRequestParameters();
+ assertThat(requestParameters.getBodyBuffer()).isNull();
+ List<Part> parts = Lists.newArrayList(requestParameters.getUploads().get("files"));
+ assertThat(parts).hasSize(2);
+ assertThat(((FilePart) parts.get(0)).getAbsolutePath()).endsWith("f1");
+ assertThat(((FilePart) parts.get(1)).getAbsolutePath()).endsWith("f2");
+ }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTestBase.java
similarity index 53%
copy from transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
copy to transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTestBase.java
index 563bf3b..7aa9535 100644
--- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTestBase.java
@@ -14,13 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.servicecomb.transport.rest.client;
import static org.apache.servicecomb.transport.rest.client.RestFeatureController.SCHEMA_ID;
-import static org.assertj.core.api.Assertions.assertThat;
-import java.util.Arrays;
import java.util.Map;
import org.apache.servicecomb.common.rest.definition.RestMetaUtils;
@@ -36,50 +33,32 @@ import org.apache.servicecomb.core.definition.InvocationRuntimeType;
import org.apache.servicecomb.core.definition.OperationMeta;
import org.apache.servicecomb.core.invocation.InvocationFactory;
import org.apache.servicecomb.core.provider.consumer.ReferenceConfig;
-import org.apache.servicecomb.core.transport.AbstractTransport;
-import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
import org.apache.servicecomb.foundation.vertx.client.http.HttpClients;
-import org.apache.servicecomb.swagger.invocation.AsyncResponse;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import com.google.common.collect.ImmutableMap;
+import io.vertx.core.http.HttpClientRequest;
-class RestClientTransportContextFactoryTest {
+public class RestClientTestBase {
static SCBEngine scbEngine;
- static Transport restTransport = new AbstractTransport() {
- @Override
- public String getName() {
- return null;
- }
+ static Transport restTransport = new FakeRestTransport();
- @Override
- public boolean init() {
- return false;
- }
+ static RestClientTransportContextFactory factory = new RestClientTransportContextFactory()
+ .setBoundaryFactory(() -> "my-boundary");
- @Override
- public void send(Invocation invocation, AsyncResponse asyncResp) {
+ ReferenceConfig referenceConfig = new ReferenceConfig(Const.RESTFUL, Const.DEFAULT_VERSION_RULE);
- }
+ OperationMeta operationMeta;
- @Override
- public Object parseAddress(String address) {
- return new URIEndpointObject(address);
- }
- };
+ RestOperationMeta restOperationMeta;
- static RestClientTransportContextFactory factory = new RestClientTransportContextFactory()
- .setBoundaryFactory(BoundaryFactory.DEFAULT);
-
- static OperationMeta operationMeta;
+ Invocation invocation;
- static RestOperationMeta restOperationMeta;
+ RestClientTransportContext transportContext;
- static ReferenceConfig referenceConfig = new ReferenceConfig(Const.RESTFUL, Const.DEFAULT_VERSION_RULE);
+ HttpClientRequest httpClientRequest;
@BeforeAll
static void beforeAll() {
@@ -87,10 +66,6 @@ class RestClientTransportContextFactoryTest {
scbEngine = SCBBootstrap.createSCBEngineForTest()
.addProducerMeta(SCHEMA_ID, new RestFeatureController())
.run();
- operationMeta = scbEngine.getProducerMicroserviceMeta()
- .ensureFindSchemaMeta(SCHEMA_ID)
- .ensureFindOperation("query");
- restOperationMeta = RestMetaUtils.getRestOperationMeta(operationMeta);
HttpClients.load();
}
@@ -102,67 +77,24 @@ class RestClientTransportContextFactoryTest {
ArchaiusUtils.resetConfig();
}
- Invocation invocation;
-
- RestClientTransportContext transportContext;
+ void init(String operationId, Map<String, Object> swaggerArgs, boolean ssl) {
+ operationMeta = scbEngine.getProducerMicroserviceMeta()
+ .ensureFindSchemaMeta(SCHEMA_ID)
+ .ensureFindOperation(operationId);
+ restOperationMeta = RestMetaUtils.getRestOperationMeta(operationMeta);
- void initInvocation(Map<String, Object> swaggerArgs, boolean ssl) {
invocation = InvocationFactory.forConsumer(
referenceConfig, operationMeta, new InvocationRuntimeType(null), swaggerArgs);
String url = "rest://localhost:1234?sslEnabled=" + ssl;
invocation.setEndpoint(new Endpoint(restTransport, url));
- }
-
- String absoluteURI() {
- return transportContext.getHttpClientRequest().absoluteURI();
- }
-
- @Test
- void should_create_without_ssl() {
- initInvocation(null, false);
transportContext = factory.create(invocation);
- assertThat(absoluteURI()).isEqualTo("http://localhost:1234/query");
+ invocation.setTransportContext(transportContext);
+ httpClientRequest = transportContext.getHttpClientRequest();
}
- @Test
- void should_create_with_ssl() {
- initInvocation(null, true);
-
- transportContext = factory.create(invocation);
- assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query");
- }
-
- @Test
- void should_create_with_query() {
- initInvocation(ImmutableMap.of("query", "value"), true);
-
- transportContext = factory.create(invocation);
- assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=value");
- }
-
- @Test
- void should_create_with_query_list() {
- initInvocation(ImmutableMap.of("query", Arrays.asList("v1", "v2")), true);
-
- transportContext = factory.create(invocation);
- assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2");
- }
-
- @Test
- void should_create_with_query_array() {
- initInvocation(ImmutableMap.of("query", new String[] {"v1", "v2"}), true);
-
- transportContext = factory.create(invocation);
- assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2");
- }
-
- @Test
- void should_get_local_address_as_not_connected_before_connect() {
- initInvocation(null, true);
-
- transportContext = factory.create(invocation);
- assertThat(transportContext.getLocalAddress()).isEqualTo("not connected");
+ String absoluteURI() {
+ return httpClientRequest.absoluteURI();
}
-}
\ No newline at end of file
+}
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
index 563bf3b..e2c3c64 100644
--- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientTransportContextFactoryTest.java
@@ -17,152 +17,83 @@
package org.apache.servicecomb.transport.rest.client;
-import static org.apache.servicecomb.transport.rest.client.RestFeatureController.SCHEMA_ID;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Map;
-import org.apache.servicecomb.common.rest.definition.RestMetaUtils;
-import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
-import org.apache.servicecomb.config.ConfigUtil;
-import org.apache.servicecomb.core.Const;
-import org.apache.servicecomb.core.Endpoint;
-import org.apache.servicecomb.core.Invocation;
-import org.apache.servicecomb.core.SCBEngine;
-import org.apache.servicecomb.core.Transport;
-import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
-import org.apache.servicecomb.core.definition.InvocationRuntimeType;
-import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.core.invocation.InvocationFactory;
-import org.apache.servicecomb.core.provider.consumer.ReferenceConfig;
-import org.apache.servicecomb.core.transport.AbstractTransport;
-import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
-import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
-import org.apache.servicecomb.foundation.vertx.client.http.HttpClients;
-import org.apache.servicecomb.swagger.invocation.AsyncResponse;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableMap;
-class RestClientTransportContextFactoryTest {
- static SCBEngine scbEngine;
-
- static Transport restTransport = new AbstractTransport() {
- @Override
- public String getName() {
- return null;
- }
-
- @Override
- public boolean init() {
- return false;
- }
-
- @Override
- public void send(Invocation invocation, AsyncResponse asyncResp) {
-
- }
-
- @Override
- public Object parseAddress(String address) {
- return new URIEndpointObject(address);
- }
- };
-
- static RestClientTransportContextFactory factory = new RestClientTransportContextFactory()
- .setBoundaryFactory(BoundaryFactory.DEFAULT);
-
- static OperationMeta operationMeta;
-
- static RestOperationMeta restOperationMeta;
-
- static ReferenceConfig referenceConfig = new ReferenceConfig(Const.RESTFUL, Const.DEFAULT_VERSION_RULE);
-
- @BeforeAll
- static void beforeAll() {
- ConfigUtil.installDynamicConfig();
- scbEngine = SCBBootstrap.createSCBEngineForTest()
- .addProducerMeta(SCHEMA_ID, new RestFeatureController())
- .run();
- operationMeta = scbEngine.getProducerMicroserviceMeta()
- .ensureFindSchemaMeta(SCHEMA_ID)
- .ensureFindOperation("query");
- restOperationMeta = RestMetaUtils.getRestOperationMeta(operationMeta);
- HttpClients.load();
- }
-
- @AfterAll
- static void afterAll() {
- scbEngine.destroy();
- HttpClients.destroy();
-
- ArchaiusUtils.resetConfig();
- }
-
- Invocation invocation;
-
- RestClientTransportContext transportContext;
-
- void initInvocation(Map<String, Object> swaggerArgs, boolean ssl) {
- invocation = InvocationFactory.forConsumer(
- referenceConfig, operationMeta, new InvocationRuntimeType(null), swaggerArgs);
-
- String url = "rest://localhost:1234?sslEnabled=" + ssl;
- invocation.setEndpoint(new Endpoint(restTransport, url));
- }
-
- String absoluteURI() {
- return transportContext.getHttpClientRequest().absoluteURI();
+class RestClientTransportContextFactoryTest extends RestClientTestBase {
+ void init(Map<String, Object> swaggerArgs, boolean ssl) {
+ init("query", swaggerArgs, ssl);
}
@Test
void should_create_without_ssl() {
- initInvocation(null, false);
+ init(null, false);
- transportContext = factory.create(invocation);
assertThat(absoluteURI()).isEqualTo("http://localhost:1234/query");
}
@Test
void should_create_with_ssl() {
- initInvocation(null, true);
+ init(null, true);
- transportContext = factory.create(invocation);
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query");
}
@Test
void should_create_with_query() {
- initInvocation(ImmutableMap.of("query", "value"), true);
+ init(ImmutableMap.of("query", "value"), true);
- transportContext = factory.create(invocation);
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=value");
}
@Test
+ void should_ignore_null_query_value() {
+ Map<String, Object> swaggerArgs = new HashMap<>();
+ swaggerArgs.put("query", null);
+ init(swaggerArgs, true);
+
+ assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query");
+ }
+
+ @Test
void should_create_with_query_list() {
- initInvocation(ImmutableMap.of("query", Arrays.asList("v1", "v2")), true);
+ init(ImmutableMap.of("query", Arrays.asList("v1", "v2")), true);
- transportContext = factory.create(invocation);
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2");
}
@Test
+ void should_ignore_null_in_query_list() {
+ init(ImmutableMap.of("query", Arrays.asList("v1", null)), true);
+
+ assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1");
+ }
+
+ @Test
void should_create_with_query_array() {
- initInvocation(ImmutableMap.of("query", new String[] {"v1", "v2"}), true);
+ init(ImmutableMap.of("query", new String[] {"v1", "v2"}), true);
- transportContext = factory.create(invocation);
assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1&query=v2");
}
@Test
+ void should_ignore_null_in_query_array() {
+ init(ImmutableMap.of("query", new String[] {"v1", null}), true);
+
+ assertThat(absoluteURI()).isEqualTo("https://localhost:1234/query?query=v1");
+ }
+
+ @Test
void should_get_local_address_as_not_connected_before_connect() {
- initInvocation(null, true);
+ init(null, true);
- transportContext = factory.create(invocation);
assertThat(transportContext.getLocalAddress()).isEqualTo("not connected");
}
}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
index a11f10f..1b567d7 100644
--- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestFeatureController.java
@@ -16,7 +16,14 @@
*/
package org.apache.servicecomb.transport.rest.client;
+import java.io.File;
+import java.util.List;
+
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
@@ -29,4 +36,40 @@ public class RestFeatureController {
public String query(@QueryParam("query") String query) {
return query;
}
+
+ @GET
+ @Path("/header")
+ public String header(@HeaderParam("header") String header) {
+ return header;
+ }
+
+ @GET
+ @Path("/cookie")
+ public String cookie(@CookieParam("cookie1") String cookie1, @CookieParam("cookie2") String cookie2) {
+ return cookie1 + ":" + cookie2;
+ }
+
+ @POST
+ @Path("/form")
+ public String form(@FormParam("form1") String form1, @FormParam("form2") String form2) {
+ return form1 + ":" + form2;
+ }
+
+ @POST
+ @Path("/formWithUpload")
+ public String formWithUpload(@FormParam("form1") String form1, @FormParam("form2") File form2) {
+ return form1 + ":" + form2.getName();
+ }
+
+ @POST
+ @Path("/formWithUploadList")
+ public String formWithUploadList(@FormParam("files") List<File> files) {
+ return files.toString();
+ }
+
+ @POST
+ @Path("/body")
+ public String body(String body) {
+ return body;
+ }
}