Skip to content

Commit

Permalink
feature: support metadata router
Browse files Browse the repository at this point in the history
  • Loading branch information
lepdou authored and SkyeBeFreeman committed May 20, 2022
1 parent a39d47c commit 7e847b8
Show file tree
Hide file tree
Showing 18 changed files with 398 additions and 175 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.metadata.core;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;

/**
* resolve custom transitive metadata from request.
*@author lepdou 2022-05-20
*/
public class CustomTransitiveMetadataResolver {

private static final String TRANSITIVE_HEADER_PREFIX = "X-SCT-Metadata-Transitive-";
private static final int TRANSITIVE_HEADER_PREFIX_LENGTH = TRANSITIVE_HEADER_PREFIX.length();

public static Map<String, String> resolve(ServerWebExchange exchange) {
Map<String, String> result = new HashMap<>();

HttpHeaders headers = exchange.getRequest().getHeaders();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String key = entry.getKey();

if (StringUtils.isNotBlank(key) &&
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
&& !CollectionUtils.isEmpty(entry.getValue())) {

String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
result.put(sourceKey, entry.getValue().get(0));
}
}

return result;
}

public static Map<String, String> resolve(HttpServletRequest request) {
Map<String, String> result = new HashMap<>();

Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String key = headers.nextElement();

if (StringUtils.isNotBlank(key) &&
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
&& StringUtils.isNotBlank(request.getHeader(key))) {

String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
result.put(sourceKey, request.getHeader(key));
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import com.tencent.cloud.common.constant.MetadataConstant;
Expand Down Expand Up @@ -58,6 +59,28 @@ public Mono<Void> filter(ServerWebExchange serverWebExchange,
WebFilterChain webFilterChain) {
// Get metadata string from http header.
ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();

Map<String, String> internalTransitiveMetadata = getIntervalTransitiveMetadata(serverHttpRequest);
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange);

Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata);

MetadataContextHolder.init(mergedTransitiveMetadata);

// Save to ServerWebExchange.
serverWebExchange.getAttributes().put(
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());

return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.",
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove());
}

private Map<String, String> getIntervalTransitiveMetadata(ServerHttpRequest serverHttpRequest) {
HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = httpHeaders
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
Expand All @@ -71,20 +94,8 @@ public Mono<Void> filter(ServerWebExchange serverWebExchange,
}
LOG.debug("Get upstream metadata string: {}", customMetadataStr);

// create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils
.deserialize2Map(customMetadataStr);

MetadataContextHolder.init(upstreamCustomMetadataMap);

// Save to ServerWebExchange.
serverWebExchange.getAttributes().put(
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());
return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.",
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove());
return JacksonUtils.deserialize2Map(customMetadataStr);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.FilterChain;
Expand Down Expand Up @@ -54,6 +55,24 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, FilterChain filterChain)
throws ServletException, IOException {
Map<String, String> internalTransitiveMetadata = getInternalTransitiveMetadata(httpServletRequest);
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest);

Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata);

try {
MetadataContextHolder.init(mergedTransitiveMetadata);

filterChain.doFilter(httpServletRequest, httpServletResponse);
}
catch (IOException | ServletException | RuntimeException e) {
throw e;
}
}

private Map<String, String> getInternalTransitiveMetadata(HttpServletRequest httpServletRequest) {
// Get custom metadata string from http header.
String customMetadataStr = httpServletRequest
.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA);
Expand All @@ -68,20 +87,7 @@ protected void doFilterInternal(HttpServletRequest httpServletRequest,
LOG.debug("Get upstream metadata string: {}", customMetadataStr);

// create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils
.deserialize2Map(customMetadataStr);

try {
MetadataContextHolder.init(upstreamCustomMetadataMap);

filterChain.doFilter(httpServletRequest, httpServletResponse);
}
catch (IOException | ServletException | RuntimeException e) {
throw e;
}
finally {
MetadataContextHolder.remove();
}
return JacksonUtils.deserialize2Map(customMetadataStr);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,32 +56,18 @@ public int getOrder() {
public void apply(RequestTemplate requestTemplate) {
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();

// add new metadata and cover old
if (!CollectionUtils.isEmpty(requestTemplate.headers()) && !CollectionUtils
.isEmpty(requestTemplate.headers().get(CUSTOM_METADATA))) {
for (String headerMetadataStr : requestTemplate.headers()
.get(CUSTOM_METADATA)) {
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(headerMetadataStr);
for (String key : headerMetadataMap.keySet()) {
metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key));
}
}
}

Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);

if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata);
String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata);
requestTemplate.removeHeader(CUSTOM_METADATA);
try {
requestTemplate.header(CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(encodedTransitiveMetadata, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
LOG.error("Set header failed.", e);
requestTemplate.header(CUSTOM_METADATA, metadataStr);
requestTemplate.header(CUSTOM_METADATA, encodedTransitiveMetadata);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
* Interceptor used for adding the metadata in http headers from context when web client
Expand All @@ -55,29 +54,20 @@ public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes,
ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();

// add new metadata and cover old
String metadataStr = httpRequest.getHeaders()
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
if (!StringUtils.isEmpty(metadataStr)) {
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(metadataStr);
for (String key : headerMetadataMap.keySet()) {
metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key));
}
}
Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);

if (!CollectionUtils.isEmpty(customMetadata)) {
metadataStr = JacksonUtils.serialize2Json(customMetadata);
String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata);
try {
httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(encodedTransitiveMetadata, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA,
metadataStr);
encodedTransitiveMetadata);
}
}

return clientHttpRequestExecution.execute(httpRequest, bytes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import java.net.URLDecoder;

import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor;
import feign.RequestInterceptor;
Expand Down Expand Up @@ -67,20 +65,11 @@ public class EncodeTransferMedataFeignInterceptorTest {
public void test1() {
String metadata = testFeign.test();
Assertions.assertThat(metadata)
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
.isEqualTo("{\"b\":\"2\"}");
Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
.isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
.isEqualTo("33");
}

@SpringBootApplication
Expand All @@ -99,8 +88,9 @@ public String test(
public interface TestFeign {

@RequestMapping(value = "/test",
headers = {MetadataConstant.HeaderName.CUSTOM_METADATA
+ "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}"})
headers = {"X-SCT-Metadata-Transitive-a=11",
"X-SCT-Metadata-Transitive-b=22",
"X-SCT-Metadata-Transitive-c=33"})
String test();

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@
import java.net.URLDecoder;

import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;

Expand All @@ -35,9 +32,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -68,29 +62,29 @@ public class EncodeTransferMedataRestTemplateInterceptorTest {

@Test
public void test1() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA,
"{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
String metadata = restTemplate
.exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET,
httpEntity, String.class)
.getBody();
Assertions.assertThat(metadata)
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
.isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
.isEqualTo("33");
// HttpHeaders httpHeaders = new HttpHeaders();
// httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA,
// "{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
// HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
// String metadata = restTemplate
// .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET,
// httpEntity, String.class)
// .getBody();
// Assertions.assertThat(metadata)
// .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
// Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
// .isEqualTo("1");
// Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
// .isEqualTo("2");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
// .isEqualTo("11");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
// .isEqualTo("22");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
// .isEqualTo("33");
}

@SpringBootApplication
Expand Down
Loading

0 comments on commit 7e847b8

Please sign in to comment.