fix: sanitize forwarded feign headers
This commit is contained in:
parent
d49341204c
commit
2a7be2ca92
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.red.circle.framework.web.feign;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.request.RequestHeaderConstant;
|
||||||
|
import com.red.circle.framework.core.request.ServiceTraceId;
|
||||||
|
import feign.RequestInterceptor;
|
||||||
|
import feign.RequestTemplate;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward only business headers to Feign requests.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||||
|
public class FeignRequestInterceptor implements RequestInterceptor {
|
||||||
|
|
||||||
|
private static final String INNER_SERVICE = "FEIGN";
|
||||||
|
|
||||||
|
private static final List<String> FORWARD_HEADERS = List.of(
|
||||||
|
RequestHeaderConstant.AUTHORIZATION,
|
||||||
|
RequestHeaderConstant.REQ_SYS_ORIGIN,
|
||||||
|
RequestHeaderConstant.REQ_CLIENT,
|
||||||
|
RequestHeaderConstant.REQ_ZONE,
|
||||||
|
RequestHeaderConstant.REQ_IMEI,
|
||||||
|
RequestHeaderConstant.REQ_APP_INTEL,
|
||||||
|
RequestHeaderConstant.REQ_VERSION,
|
||||||
|
RequestHeaderConstant.REQ_LANG,
|
||||||
|
RequestHeaderConstant.REQ_INNER_INTERNAL,
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final Set<String> BLOCKED_HEADERS = Set.of(
|
||||||
|
"host",
|
||||||
|
"content-length",
|
||||||
|
"transfer-encoding",
|
||||||
|
"connection",
|
||||||
|
"keep-alive",
|
||||||
|
"upgrade",
|
||||||
|
"proxy-authorization",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"te",
|
||||||
|
"trailer"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(RequestTemplate requestTemplate) {
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
|
||||||
|
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attrs) {
|
||||||
|
forwardHeaders(requestTemplate, attrs.getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_SERVICE)) {
|
||||||
|
requestTemplate.header(RequestHeaderConstant.REQ_INNER_SERVICE, INNER_SERVICE);
|
||||||
|
}
|
||||||
|
if (!hasHeader(requestTemplate, RequestHeaderConstant.REQ_INNER_TRACE_ID)) {
|
||||||
|
requestTemplate.header(
|
||||||
|
RequestHeaderConstant.REQ_INNER_TRACE_ID,
|
||||||
|
ServiceTraceId.genTraceId(ServiceTraceId.Origin.INNER_REQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBlockedHeaders(requestTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forwardHeaders(RequestTemplate requestTemplate, HttpServletRequest request) {
|
||||||
|
for (String header : FORWARD_HEADERS) {
|
||||||
|
String value = request.getHeader(header);
|
||||||
|
if (hasHeader(requestTemplate, header) || !isUsableHeaderValue(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
requestTemplate.header(header, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBlockedHeaders(RequestTemplate requestTemplate) {
|
||||||
|
List<String> names = new ArrayList<>(requestTemplate.headers().keySet());
|
||||||
|
for (String name : names) {
|
||||||
|
if (isBlockedHeader(name)) {
|
||||||
|
requestTemplate.removeHeader(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHeader(RequestTemplate requestTemplate, String header) {
|
||||||
|
return requestTemplate.headers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBlockedHeader(String header) {
|
||||||
|
if (header == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String normalized = header.toLowerCase(Locale.ROOT);
|
||||||
|
return BLOCKED_HEADERS.contains(normalized) || normalized.startsWith("proxy-");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isUsableHeaderValue(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c < 32 || c == 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user