From e8cf276fce4ffe6787857f821ae395abf4bfd729 Mon Sep 17 00:00:00 2001
From: hongqiaowei
Date: Mon, 20 Feb 2023 18:18:15 +0800
Subject: [PATCH 1/8] Support request path end with or without /
---
.../fizzgate/plugin/auth/ServiceConfig.java | 29 +++++++++----------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java b/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java
index 292522e..1396879 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/auth/ServiceConfig.java
@@ -18,6 +18,7 @@
package com.fizzgate.plugin.auth;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fizzgate.util.Consts;
import com.fizzgate.util.ThreadContext;
import com.fizzgate.util.UrlTransformUtils;
@@ -124,18 +125,22 @@ public class ServiceConfig {
}
private void checkPathPattern(Map> pathPattern2apiConfigMap, boolean dedicatedLineRequest, String path, ArrayList result) {
+ String path0 = path;
+ if (!path.equals(Consts.S.FORWARD_SLASH_STR)) {
+ int lastCharPos = path.length() - 1;
+ char c = path.charAt(lastCharPos);
+ if (c == Consts.S.FORWARD_SLASH) {
+ path0 = path.substring(0, lastCharPos);
+ } else {
+ path0 = path + Consts.S.FORWARD_SLASH;
+ }
+ }
Set>> entries = pathPattern2apiConfigMap.entrySet();
- // boolean clear = false;
for (Map.Entry> entry : entries) {
String pathPattern = entry.getKey();
Set apiConfigs = entry.getValue();
- if (pathPattern.equals(path)) {
+ if (pathPattern.equals(path) || pathPattern.equals(path0)) {
for (ApiConfig ac : apiConfigs) {
-// if (ac.allowAccess) {
- /*if (!clear && !result.isEmpty()) {
- result.clear();
- clear = true;
- }*/
if (dedicatedLineRequest) {
if (ac.dedicatedLine) {
result.add(ac);
@@ -145,14 +150,9 @@ public class ServiceConfig {
result.add(ac);
}
}
-// }
}
- /*if (clear && !result.isEmpty()) {
- return;
- }*/
- } else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
+ } else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path) || UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path0)) {
for (ApiConfig ac : apiConfigs) {
-// if (ac.allowAccess) {
if (dedicatedLineRequest) {
if (ac.dedicatedLine) {
result.add(ac);
@@ -162,9 +162,8 @@ public class ServiceConfig {
result.add(ac);
}
}
-// }
}
}
- } // end for
+ }
}
}
From 6052760f4ca8eebd2639f338c1fa911b56951e6f Mon Sep 17 00:00:00 2001
From: Francis Dong
Date: Thu, 16 Mar 2023 11:59:25 +0800
Subject: [PATCH 2/8] Support HMAC algorithm functions #470
---
.../com/fizzgate/fizz/function/CodecFunc.java | 34 ++++++++++++++++++-
.../fizz/function/CodecFuncTests.java | 7 ++++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
index 23ad4b1..8044e04 100644
--- a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
+++ b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
@@ -27,6 +27,8 @@ import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.apache.commons.codec.digest.HmacAlgorithms;
+import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,7 +48,7 @@ public class CodecFunc implements IFunc {
private static final String CHARSET_UTF8 = "UTF-8";
private static final String IV = "12345678";
-
+
private static CodecFunc singleton;
public static CodecFunc getInstance() {
@@ -77,6 +79,12 @@ public class CodecFunc implements IFunc {
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.aesDecrypt", this);
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desEncrypt", this);
FuncExecutor.register(NAME_SPACE_PREFIX + "codec.desDecrypt", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacMd5", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha1", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha224", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha256", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha384", this);
+ FuncExecutor.register(NAME_SPACE_PREFIX + "codec.hmacSha512", this);
}
public String md5(String data) {
@@ -180,5 +188,29 @@ public class CodecFunc implements IFunc {
throw e;
}
}
+
+ public String hmacMd5(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_MD5, secretKey).hmacHex(data);
+ }
+
+ public String hmacSha1(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, secretKey).hmacHex(data);
+ }
+
+ public String hmacSha224(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_SHA_224, secretKey).hmacHex(data);
+ }
+
+ public String hmacSha256(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(data);
+ }
+
+ public String hmacSha384(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, secretKey).hmacHex(data);
+ }
+
+ public String hmacSha512(String secretKey, String data) {
+ return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, secretKey).hmacHex(data);
+ }
}
diff --git a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
index 750abc9..4c79872 100644
--- a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
+++ b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
@@ -122,5 +122,12 @@ class CodecFuncTests {
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
assertEquals("abc", result.toString());
}
+
+ @Test
+ void testHmacSha256() {
+ String funcExpression = "fn.codec.hmacSha256(\"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\", \"12345678123456781234567812345678\")";
+ Object result = FuncExecutor.getInstance().exec(null, funcExpression);
+ assertEquals("c61be0237ec186df1c5f51425e607093b260a76e5de43a62cb3e821103303990", result.toString());
+ }
}
\ No newline at end of file
From 49134c52d6df61110bdcda6589aa4dd4aa947fcf Mon Sep 17 00:00:00 2001
From: Francis Dong
Date: Thu, 16 Mar 2023 14:31:47 +0800
Subject: [PATCH 3/8] Support HMAC algorithm functions #470
---
.../java/com/fizzgate/fizz/function/CodecFunc.java | 12 ++++++------
.../com/fizzgate/fizz/function/CodecFuncTests.java | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
index 8044e04..23553cc 100644
--- a/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
+++ b/fizz-core/src/main/java/com/fizzgate/fizz/function/CodecFunc.java
@@ -189,27 +189,27 @@ public class CodecFunc implements IFunc {
}
}
- public String hmacMd5(String secretKey, String data) {
+ public String hmacMd5(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_MD5, secretKey).hmacHex(data);
}
- public String hmacSha1(String secretKey, String data) {
+ public String hmacSha1(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, secretKey).hmacHex(data);
}
- public String hmacSha224(String secretKey, String data) {
+ public String hmacSha224(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_224, secretKey).hmacHex(data);
}
- public String hmacSha256(String secretKey, String data) {
+ public String hmacSha256(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(data);
}
- public String hmacSha384(String secretKey, String data) {
+ public String hmacSha384(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, secretKey).hmacHex(data);
}
- public String hmacSha512(String secretKey, String data) {
+ public String hmacSha512(String data, String secretKey) {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, secretKey).hmacHex(data);
}
diff --git a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
index 4c79872..0c1609b 100644
--- a/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
+++ b/fizz-core/src/test/java/com/fizzgate/fizz/function/CodecFuncTests.java
@@ -125,7 +125,7 @@ class CodecFuncTests {
@Test
void testHmacSha256() {
- String funcExpression = "fn.codec.hmacSha256(\"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\", \"12345678123456781234567812345678\")";
+ String funcExpression = "fn.codec.hmacSha256(\"12345678123456781234567812345678\", \"635e8562b968bc05bb80cacf124ebd53285280ee6845df0000faa33acafc38f0\")";
Object result = FuncExecutor.getInstance().exec(null, funcExpression);
assertEquals("c61be0237ec186df1c5f51425e607093b260a76e5de43a62cb3e821103303990", result.toString());
}
From 491f6d399afd85e0ad20d09384b1894109f35330 Mon Sep 17 00:00:00 2001
From: hongqiaowei
Date: Sat, 4 Mar 2023 11:43:05 +0800
Subject: [PATCH 4/8] Fix flow control problem
---
fizz-bootstrap/pom.xml | 4 +-
fizz-common/pom.xml | 2 +-
fizz-core/pom.xml | 2 +-
.../filter/FilterExceptionHandlerConfig.java | 14 +-
.../com/fizzgate/filter/FizzLogFilter.java | 4 +-
.../fizzgate/filter/FlowControlFilter.java | 126 +++++++++---------
.../com/fizzgate/filter/PreprocessFilter.java | 19 ++-
.../java/com/fizzgate/filter/RouteFilter.java | 106 +++++++--------
.../plugin/FizzPluginFilterChain.java | 12 ++
.../com/fizzgate/plugin/PluginFilter.java | 11 +-
.../plugin/auth/AuthPluginFilter.java | 1 -
.../plugin/requestbody/RequestBodyPlugin.java | 23 +++-
.../plugin/stat/StatPluginFilter.java | 1 +
.../com/fizzgate/proxy/FizzWebClient.java | 10 +-
.../java/com/fizzgate/stats/FlowStat.java | 32 ++---
fizz-plugin/pom.xml | 2 +-
fizz-spring-boot-starter/pom.xml | 2 +-
pom.xml | 38 +++++-
18 files changed, 231 insertions(+), 178 deletions(-)
diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml
index f30a1a4..b95c7f0 100644
--- a/fizz-bootstrap/pom.xml
+++ b/fizz-bootstrap/pom.xml
@@ -6,7 +6,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.1
+ 2.7.2-SNAPSHOT
../pom.xml
@@ -18,7 +18,7 @@
Dragonfruit-SR3
Dysprosium-SR25
5.3.7.RELEASE
- 4.1.89.Final
+ 4.1.90.Final
4.4.16
2.17.2
1.7.36
diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml
index 9953932..e3e6140 100644
--- a/fizz-common/pom.xml
+++ b/fizz-common/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.1
+ 2.7.2-SNAPSHOT
../pom.xml
4.0.0
diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml
index d4278cd..4f67eed 100644
--- a/fizz-core/pom.xml
+++ b/fizz-core/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.1
+ 2.7.2-SNAPSHOT
../pom.xml
4.0.0
diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java b/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java
index c71bf75..e773488 100644
--- a/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java
+++ b/fizz-core/src/main/java/com/fizzgate/filter/FilterExceptionHandlerConfig.java
@@ -56,13 +56,19 @@ public class FilterExceptionHandlerConfig {
public static class FilterExceptionHandler implements WebExceptionHandler {
- private static final Logger log = LoggerFactory.getLogger(FilterExceptionHandler.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(FilterExceptionHandler.class);
private static final String filterExceptionHandler = "filterExceptionHandler";
@Override
public Mono handle(ServerWebExchange exchange, Throwable t) {
exchange.getAttributes().put(WebUtils.ORIGINAL_ERROR, t);
String traceId = WebUtils.getTraceId(exchange);
+
+ if (LOGGER.isDebugEnabled()) {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ LOGGER.debug(Consts.S.EMPTY, t);
+ }
+
ServerHttpResponse resp = exchange.getResponse();
if (SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) {
if (t instanceof ResponseStatusException) {
@@ -113,9 +119,8 @@ public class FilterExceptionHandlerConfig {
if (t instanceof FizzRuntimeException) {
FizzRuntimeException ex = (FizzRuntimeException) t;
- // log.error(traceId + ' ' + tMsg, LogService.BIZ_ID, traceId, ex);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
- log.error(traceId + ' ' + tMsg, ex);
+ LOGGER.error(tMsg, ex);
respHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
RespEntity rs = null;
if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
@@ -132,9 +137,8 @@ public class FilterExceptionHandlerConfig {
if (fc == null) { // t came from flow control filter
StringBuilder b = ThreadContext.getStringBuilder();
WebUtils.request2stringBuilder(exchange, b);
- // log.error(b.toString(), LogService.BIZ_ID, traceId, t);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
- log.error(b.toString(), t);
+ LOGGER.error(b.toString(), t);
String s = WebUtils.jsonRespBody(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId);
respHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
vm = resp.writeWith(Mono.just(resp.bufferFactory().wrap(s.getBytes())));
diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java
index 9878ce4..9fa7e0b 100644
--- a/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/filter/FizzLogFilter.java
@@ -51,14 +51,14 @@ public class FizzLogFilter implements WebFilter {
long start = System.currentTimeMillis();
return chain.filter(exchange).doFinally(
(c) -> {
- if (log.isInfoEnabled()) {
+ if (log.isDebugEnabled()) {
StringBuilder b = ThreadContext.getStringBuilder();
WebUtils.request2stringBuilder(exchange, b);
b.append(resp).append(exchange.getResponse().getStatusCode())
.append(in) .append(System.currentTimeMillis() - start);
// log.info(b.toString(), LogService.BIZ_ID, WebUtils.getTraceId(exchange));
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange));
- log.info(b.toString());
+ log.debug(b.toString());
}
}
);
diff --git a/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java
index 6446d11..8eb7bd3 100644
--- a/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/filter/FlowControlFilter.java
@@ -17,19 +17,6 @@
package com.fizzgate.filter;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.annotation.Order;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.stereotype.Component;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.WebFilterChain;
-
import com.fizzgate.config.SystemConfig;
import com.fizzgate.monitor.FizzMonitorService;
import com.fizzgate.plugin.auth.ApiConfigService;
@@ -44,7 +31,19 @@ import com.fizzgate.stats.degrade.DegradeRule;
import com.fizzgate.stats.ratelimit.ResourceRateLimitConfig;
import com.fizzgate.stats.ratelimit.ResourceRateLimitConfigService;
import com.fizzgate.util.*;
-
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.core.publisher.SignalType;
@@ -63,7 +62,7 @@ public class FlowControlFilter extends FizzWebFilter {
public static final String FLOW_CONTROL_FILTER = "flowControlFilter";
- private static final Logger log = LoggerFactory.getLogger(FlowControlFilter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(FlowControlFilter.class);
private static final String admin = "admin";
@@ -160,7 +159,6 @@ public class FlowControlFilter extends FizzWebFilter {
if (!favReq && flowControlFilterProperties.isFlowControl() && !adminReq && !proxyTestReq && !fizzApiReq) {
String traceId = WebUtils.getTraceId(exchange);
- // LogService.setBizId(traceId);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
if (!apiConfigService.serviceConfigMap.containsKey(service)) {
String json = WebUtils.jsonRespBody(HttpStatus.FORBIDDEN.value(), "no service " + service + " in flow config", traceId);
@@ -178,12 +176,10 @@ public class FlowControlFilter extends FizzWebFilter {
});
if (result != null && !result.isSuccess()) {
- long currentTimeMillis = System.currentTimeMillis();
String blockedResourceId = result.getBlockedResourceId();
if (BlockType.CIRCUIT_BREAK == result.getBlockType()) {
fizzMonitorService.alarm(service, path, FizzMonitorService.CIRCUIT_BREAK_ALARM, null);
- // log.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
- log.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId);
+ LOGGER.info("{} trigger {} circuit breaker limit", traceId, blockedResourceId);
String responseContentType = flowControlFilterProperties.getDegradeDefaultResponseContentType();
String responseContent = flowControlFilterProperties.getDegradeDefaultResponseContent();
@@ -214,12 +210,10 @@ public class FlowControlFilter extends FizzWebFilter {
} else {
if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) {
fizzMonitorService.alarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, concurrents);
- // log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
- log.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId);
+ LOGGER.info("{} exceed {} flow limit, blocked by maximum concurrent requests", traceId, blockedResourceId);
} else {
fizzMonitorService.alarm(service, path, FizzMonitorService.RATE_LIMIT_ALARM, qps);
- // log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId, LogService.BIZ_ID, traceId);
- log.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId);
+ LOGGER.info("{} exceed {} flow limit, blocked by maximum QPS", traceId, blockedResourceId);
}
ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceIdUtils.NODE_RESOURCE);
@@ -240,42 +234,50 @@ public class FlowControlFilter extends FizzWebFilter {
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rc.getBytes())));
}
} else {
- long start = System.currentTimeMillis();
- setTraceId(exchange);
- String finalService = service;
- String finalPath = path;
- return chain.filter(exchange).doFinally(s -> {
- long rt = System.currentTimeMillis() - start;
- CircuitBreaker cb = exchange.getAttribute(CircuitBreaker.DETECT_REQUEST);
- HttpStatus statusCode = exchange.getResponse().getStatusCode();
- Throwable t = exchange.getAttribute(WebUtils.ORIGINAL_ERROR);
- if (t instanceof TimeoutException) {
- statusCode = HttpStatus.GATEWAY_TIMEOUT;
- }
- // if (s == SignalType.ON_ERROR || statusCode.is4xxClientError() || statusCode.is5xxServerError()) {
- if (s == SignalType.ON_ERROR || statusCode.is5xxServerError()) {
- flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false, statusCode);
- if (cb != null) {
- cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.OPEN, currentTimeSlot, flowStat);
- }
- if (statusCode == HttpStatus.GATEWAY_TIMEOUT) {
- fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.TIMEOUT_ALARM, t.getMessage());
- } else if (statusCode.is5xxServerError()) {
- fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, String.valueOf(statusCode.value()));
- } else if (s == SignalType.ON_ERROR && t != null) {
- fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, t.getMessage());
- }
- } else {
- flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true, statusCode);
- if (cb != null) {
- cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeSlot, flowStat);
- }
- }
- });
+ long start = System.currentTimeMillis();
+ String finalService = service;
+ String finalPath = path;
+ return chain.filter(exchange).doFinally(s -> {
+
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ long rt = System.currentTimeMillis() - start;
+ CircuitBreaker cb = exchange.getAttribute(CircuitBreaker.DETECT_REQUEST);
+ HttpStatus statusCode = exchange.getResponse().getStatusCode();
+ Throwable t = exchange.getAttribute(WebUtils.ORIGINAL_ERROR);
+ if (t instanceof TimeoutException) {
+ statusCode = HttpStatus.GATEWAY_TIMEOUT;
+ }
+
+ if (s == SignalType.ON_ERROR || statusCode.is5xxServerError()) {
+ flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false, statusCode);
+ if (cb != null) {
+ cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.OPEN, currentTimeSlot, flowStat);
+ }
+ if (statusCode == HttpStatus.GATEWAY_TIMEOUT) {
+ fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.TIMEOUT_ALARM, t.getMessage());
+ } else if (statusCode.is5xxServerError()) {
+ fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, String.valueOf(statusCode.value()));
+ } else if (s == SignalType.ON_ERROR && t != null) {
+ fizzMonitorService.alarm(finalService, finalPath, FizzMonitorService.ERROR_ALARM, t.getMessage());
+ }
+ } else {
+ flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true, statusCode);
+ if (cb != null) {
+ cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeSlot, flowStat);
+ }
+ }
+
+ if (s == SignalType.CANCEL) {
+ ClientResponse remoteResp = exchange.getAttribute("remoteResp");
+ if (remoteResp != null) {
+ remoteResp.bodyToMono(Void.class).subscribe();
+ LOGGER.warn("client cancel, and dispose remote response");
+ }
+ }
+ });
}
}
- // setTraceId(exchange);
return chain.filter(exchange);
}
@@ -340,15 +342,15 @@ public class FlowControlFilter extends FizzWebFilter {
check = true;
}
}
- if (log.isDebugEnabled()) {
- log.debug("getResourceConfigItselfAndParents:\n" + JacksonUtils.writeValueAsString(rc) + '\n' + JacksonUtils.writeValueAsString(result));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("getResourceConfigItselfAndParents:\n" + JacksonUtils.writeValueAsString(rc) + '\n' + JacksonUtils.writeValueAsString(result));
}
return result;
}
private List getFlowControlConfigs(String app, String ip, String node, String service, String path) {
- if (log.isDebugEnabled()) {
- log.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path);
}
boolean hasHost = (StringUtils.isNotBlank(node) && !node.equals(ResourceIdUtils.NODE));
int sz = hasHost ? 10 : 9;
@@ -377,8 +379,8 @@ public class FlowControlFilter extends FizzWebFilter {
checkRateLimitConfigAndAddTo(resourceConfigs, b, null, ip, null, service, path, null);
}
- if (log.isDebugEnabled()) {
- log.debug("resource configs: " + JacksonUtils.writeValueAsString(resourceConfigs));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("resource configs: " + JacksonUtils.writeValueAsString(resourceConfigs));
}
return resourceConfigs;
}
diff --git a/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java
index 0a30972..1060b32 100644
--- a/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/filter/PreprocessFilter.java
@@ -17,6 +17,7 @@
package com.fizzgate.filter;
+import com.fizzgate.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
@@ -35,10 +36,6 @@ import com.fizzgate.plugin.auth.GatewayGroup;
import com.fizzgate.plugin.auth.GatewayGroupService;
import com.fizzgate.plugin.stat.StatPluginFilter;
import com.fizzgate.proxy.Route;
-import com.fizzgate.util.ReactorUtils;
-import com.fizzgate.util.Result;
-import com.fizzgate.util.ThreadContext;
-import com.fizzgate.util.WebUtils;
import reactor.core.publisher.Mono;
@@ -54,7 +51,7 @@ import java.util.function.Function;
@Order(10)
public class PreprocessFilter extends FizzWebFilter {
- private static final Logger log = LoggerFactory.getLogger(PreprocessFilter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(PreprocessFilter.class);
public static final String PREPROCESS_FILTER = "preprocessFilter";
@@ -72,6 +69,12 @@ public class PreprocessFilter extends FizzWebFilter {
@Override
public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) {
+ String traceId = WebUtils.getTraceId(exchange);
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("preprocess filter start");
+ }
+
Map fc = new HashMap<>(); fc.put(WebUtils.PREV_FILTER_RESULT, succFr);
Map appendHdrs = new HashMap<>(8);
Map eas = exchange.getAttributes(); eas.put(WebUtils.FILTER_CONTEXT, fc);
@@ -85,8 +88,14 @@ public class PreprocessFilter extends FizzWebFilter {
.thenReturn(ReactorUtils.Void)
.flatMap(
v -> {
+
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+
Result auth = (Result) WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT);
if (auth.code == Result.FAIL) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("preprocess filter end 403");
+ }
return WebUtils.responseError(exchange, HttpStatus.FORBIDDEN.value(), auth.msg);
}
ApiConfig ac = auth.data;
diff --git a/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java b/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java
index 65d9863..8ea9fdd 100644
--- a/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/filter/RouteFilter.java
@@ -17,11 +17,22 @@
package com.fizzgate.filter;
+import com.fizzgate.config.SystemConfig;
+import com.fizzgate.plugin.auth.ApiConfig;
+import com.fizzgate.proxy.FizzWebClient;
+import com.fizzgate.proxy.Route;
+import com.fizzgate.proxy.dubbo.ApacheDubboGenericService;
+import com.fizzgate.proxy.dubbo.DubboInterfaceDeclaration;
+import com.fizzgate.service_registry.RegistryCenterService;
+import com.fizzgate.stats.FlowStat;
+import com.fizzgate.stats.ResourceConfig;
+import com.fizzgate.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferUtils;
+import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -32,22 +43,13 @@ import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
-
-import com.fizzgate.config.SystemConfig;
-import com.fizzgate.plugin.auth.ApiConfig;
-import com.fizzgate.proxy.FizzWebClient;
-import com.fizzgate.proxy.Route;
-import com.fizzgate.proxy.dubbo.ApacheDubboGenericService;
-import com.fizzgate.proxy.dubbo.DubboInterfaceDeclaration;
-import com.fizzgate.service_registry.RegistryCenterService;
-import com.fizzgate.util.*;
-
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* @author hongqiaowei
@@ -57,7 +59,7 @@ import java.util.function.Function;
@Order(Ordered.LOWEST_PRECEDENCE)
public class RouteFilter extends FizzWebFilter {
- private static final Logger log = LoggerFactory.getLogger(RouteFilter.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(RouteFilter.class);
@Resource
private FizzWebClient fizzWebClient;
@@ -68,6 +70,9 @@ public class RouteFilter extends FizzWebFilter {
@Resource
private SystemConfig systemConfig;
+ @Resource
+ private FlowControlFilter flowControlFilter;
+
@Override
public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) {
@@ -77,16 +82,13 @@ public class RouteFilter extends FizzWebFilter {
} else {
Mono resp = WebUtils.getDirectResponse(exchange);
if (resp == null) { // should not reach here
- ServerHttpRequest clientReq = exchange.getRequest();
String traceId = WebUtils.getTraceId(exchange);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
String msg = traceId + ' ' + pfr.id + " fail";
if (pfr.cause == null) {
- // log.error(msg, LogService.BIZ_ID, traceId);
- log.error(msg);
+ LOGGER.error(msg);
} else {
- // log.error(msg, LogService.BIZ_ID, traceId, pfr.cause);
- log.error(msg, pfr.cause);
+ LOGGER.error(msg, pfr.cause);
}
HttpStatus s = HttpStatus.INTERNAL_SERVER_ERROR;
if (!SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) {
@@ -101,8 +103,13 @@ public class RouteFilter extends FizzWebFilter {
private Mono doFilter0(ServerWebExchange exchange, WebFilterChain chain) {
- ServerHttpRequest req = exchange.getRequest();
String traceId = WebUtils.getTraceId(exchange);
+ if (LOGGER.isDebugEnabled()) {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ LOGGER.debug("route filter start");
+ }
+
+ ServerHttpRequest req = exchange.getRequest();
Route route = exchange.getAttribute(WebUtils.ROUTE);
HttpHeaders hdrs = null;
@@ -112,32 +119,17 @@ public class RouteFilter extends FizzWebFilter {
}
if (route == null) {
- /*String pathQuery = WebUtils.getClientReqPathQuery(exchange);
- return fizzWebClient.send2service(traceId, req.getMethod(), WebUtils.getClientService(exchange), pathQuery, hdrs, req.getBody(), 0, 0, 0)
- .flatMap(genServerResponse(exchange));*/
-
Map.Entry> pathQueryTemplate = WebUtils.getClientReqPathQueryTemplate(exchange).entrySet().iterator().next();
return fizzWebClient.send2service(traceId, req.getMethod(), WebUtils.getClientService(exchange), pathQueryTemplate.getKey(), hdrs, req.getBody(), 0, 0, 0, pathQueryTemplate.getValue().toArray(new String[0]))
.flatMap(genServerResponse(exchange));
} else if (route.type == ApiConfig.Type.SERVICE_DISCOVERY) {
- /*String pathQuery = getBackendPathQuery(req, route);
- String svc = RegistryCenterService.getServiceNameSpace(route.registryCenter, route.backendService);
- return fizzWebClient.send2service(traceId, route.method, svc, pathQuery, hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval)
- .flatMap(genServerResponse(exchange));*/
-
Map.Entry> pathQueryTemplate = getBackendPathQueryTemplate(req, route).entrySet().iterator().next();
String svc = RegistryCenterService.getServiceNameSpace(route.registryCenter, route.backendService);
return fizzWebClient.send2service(traceId, route.method, svc, pathQueryTemplate.getKey(), hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval, pathQueryTemplate.getValue().toArray(new String[0]))
.flatMap(genServerResponse(exchange));
} else if (route.type == ApiConfig.Type.REVERSE_PROXY) {
- /*String uri = ThreadContext.getStringBuilder().append(route.nextHttpHostPort)
- .append(getBackendPathQuery(req, route))
- .toString();
- return fizzWebClient.send(traceId, route.method, uri, hdrs, req.getBody(), route.timeout, route.retryCount, route.retryInterval)
- .flatMap(genServerResponse(exchange));*/
-
Map.Entry> pathQueryTemplate = getBackendPathQueryTemplate(req, route).entrySet().iterator().next();
String uri = ThreadContext.getStringBuilder().append(route.nextHttpHostPort)
.append(pathQueryTemplate.getKey())
@@ -150,20 +142,6 @@ public class RouteFilter extends FizzWebFilter {
}
}
- private String getBackendPathQuery(ServerHttpRequest request, Route route) {
- String qry = route.query;
- if (qry == null) {
- MultiValueMap queryParams = request.getQueryParams();
- if (queryParams.isEmpty()) {
- return route.backendPath;
- } else {
- return route.backendPath + Consts.S.QUESTION + WebUtils.toQueryString(queryParams);
- }
- } else {
- return route.backendPath + Consts.S.QUESTION + qry;
- }
- }
-
private Map> getBackendPathQueryTemplate(ServerHttpRequest request, Route route) {
String qry = route.query;
if (qry == null) {
@@ -183,6 +161,7 @@ public class RouteFilter extends FizzWebFilter {
private Function> genServerResponse(ServerWebExchange exchange) {
return remoteResp -> {
+ String traceId = WebUtils.getTraceId(exchange);
ServerHttpResponse clientResp = exchange.getResponse();
clientResp.setStatusCode(remoteResp.statusCode());
HttpHeaders clientRespHeaders = clientResp.getHeaders();
@@ -203,24 +182,36 @@ public class RouteFilter extends FizzWebFilter {
}
}
);
- if (log.isDebugEnabled()) {
+ if (LOGGER.isDebugEnabled()) {
StringBuilder b = ThreadContext.getStringBuilder();
- String traceId = WebUtils.getTraceId(exchange);
WebUtils.response2stringBuilder(traceId, remoteResp, b);
- // log.debug(b.toString(), LogService.BIZ_ID, traceId);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
- log.debug(b.toString());
+ LOGGER.debug(b.toString());
}
return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers()))
- .doOnError(throwable -> cleanup(remoteResp)).doOnCancel(() -> cleanup(remoteResp));
+ .doOnError(
+ t -> {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ exchange.getAttributes().put("remoteResp", remoteResp);
+ LOGGER.error("response client error", t);
+ }
+ )
+ .doOnCancel(
+ () -> {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ exchange.getAttributes().put("remoteResp", remoteResp);
+ LOGGER.error("client signal cancel");
+ // cleanup(remoteResp);
+ }
+ );
};
}
- private void cleanup(ClientResponse clientResponse) {
- if (clientResponse != null) {
- clientResponse.bodyToMono(Void.class).subscribe();
- }
- }
+ // private void cleanup(ClientResponse clientResponse) {
+ // if (clientResponse != null) {
+ // clientResponse.bodyToMono(Void.class).subscribe();
+ // }
+ // }
private Mono dubboRpc(ServerWebExchange exchange, Route route) {
final String[] ls = {null};
@@ -272,9 +263,8 @@ public class RouteFilter extends FizzWebFilter {
if (ls[0] != null) {
b.append('\n').append(ls[0]);
}
- // log.error(b.toString(), LogService.BIZ_ID, WebUtils.getTraceId(exchange), t);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange));
- log.error(b.toString(), t);
+ LOGGER.error(b.toString(), t);
}
)
;
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java b/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java
index ff50658..9fc6995 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/FizzPluginFilterChain.java
@@ -17,6 +17,9 @@
package com.fizzgate.plugin;
+import com.fizzgate.util.Consts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
@@ -38,6 +41,8 @@ import java.util.Map;
public final class FizzPluginFilterChain {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FizzPluginFilterChain.class);
+
private static final String pluginConfigsIt = "pcsit@";
public static final String WEB_FILTER_CHAIN = "wfc@";
@@ -62,6 +67,13 @@ public final class FizzPluginFilterChain {
if (it.hasNext()) {
PluginConfig pc = it.next();
FizzPluginFilter pf = Fizz.context.getBean(pc.plugin, FizzPluginFilter.class);
+
+ String traceId = WebUtils.getTraceId(exchange);
+ if (LOGGER.isDebugEnabled()) {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ LOGGER.debug("{} start", pc.plugin);
+ }
+
Mono m = pf.filter(exchange, pc.config);
if (pf instanceof PluginFilter) {
boolean f = false;
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java
index de70d66..2665019 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/PluginFilter.java
@@ -43,7 +43,7 @@ import java.util.Map;
@Deprecated
public abstract class PluginFilter implements FizzPluginFilter {
- private static final Logger log = LoggerFactory.getLogger(PluginFilter.class);
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Override
public Mono filter(ServerWebExchange exchange, Map config) {
@@ -55,9 +55,8 @@ public abstract class PluginFilter implements FizzPluginFilter {
FilterResult pfr = WebUtils.getPrevFilterResult(exchange);
String traceId = WebUtils.getTraceId(exchange);
ThreadContext.put(Consts.TRACE_ID, traceId);
- if (log.isDebugEnabled()) {
- // log.debug(traceId + ' ' + this + ": " + pfr.id + " execute " + (pfr.success ? "success" : "fail"), LogService.BIZ_ID, traceId);
- log.debug(traceId + ' ' + this + ": " + pfr.id + " execute " + (pfr.success ? "success" : "fail"));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("{} execute {}", pfr.id, pfr.success ? "success" : "fail");
}
if (pfr.success) {
return doFilter(exchange, config, fixedConfig);
@@ -65,9 +64,9 @@ public abstract class PluginFilter implements FizzPluginFilter {
if (WebUtils.getDirectResponse(exchange) == null) { // should not reach here
String msg = traceId + ' ' + pfr.id + " fail";
if (pfr.cause == null) {
- log.error(msg);
+ LOGGER.error(msg);
} else {
- log.error(msg, pfr.cause);
+ LOGGER.error(msg, pfr.cause);
}
HttpStatus s = HttpStatus.OK;
if (SystemConfig.FIZZ_ERR_RESP_HTTP_STATUS_ENABLE) {
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java
index 87312ca..1048548 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/auth/AuthPluginFilter.java
@@ -56,7 +56,6 @@ public class AuthPluginFilter extends PluginFilter {
r -> {
if (log.isDebugEnabled()) {
String traceId = WebUtils.getTraceId(exchange);
- // log.debug("{} req auth: {}", traceId, r, LogService.BIZ_ID, traceId);
ThreadContext.put(Consts.TRACE_ID, traceId);
log.debug("{} req auth: {}", traceId, r);
}
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java b/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java
index 542b034..2a53c12 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/requestbody/RequestBodyPlugin.java
@@ -46,13 +46,19 @@ import java.util.Map;
@Component(RequestBodyPlugin.REQUEST_BODY_PLUGIN)
public class RequestBodyPlugin implements FizzPluginFilter {
- private static final Logger log = LoggerFactory.getLogger(RequestBodyPlugin.class);
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass());
public static final String REQUEST_BODY_PLUGIN = "requestBodyPlugin";
@Override
public Mono filter(ServerWebExchange exchange, Map config) {
+ // String traceId = WebUtils.getTraceId(exchange);
+ // if (LOGGER.isDebugEnabled()) {
+ // org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ // LOGGER.debug("{} start", getClass().getSimpleName());
+ // }
+
ServerHttpRequest req = exchange.getRequest();
if (req instanceof FizzServerHttpRequestDecorator) {
return doFilter(exchange, config);
@@ -76,18 +82,21 @@ public class RequestBodyPlugin implements FizzPluginFilter {
if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
newExchange = new FizzServerWebExchangeDecorator(mutatedExchange);
}
- if (log.isDebugEnabled()) {
- String traceId = WebUtils.getTraceId(exchange);
- // log.debug("{} request is decorated", traceId, LogService.BIZ_ID, traceId);
- ThreadContext.put(Consts.TRACE_ID, traceId);
- log.debug("{} request is decorated", traceId);
- }
+ // if (LOGGER.isDebugEnabled()) {
+ // ThreadContext.put(Consts.TRACE_ID, traceId);
+ // LOGGER.debug("{} request is decorated", traceId);
+ // }
return doFilter(newExchange, config);
}
);
}
public Mono doFilter(ServerWebExchange exchange, Map config) {
+ String traceId = WebUtils.getTraceId(exchange);
+ if (LOGGER.isDebugEnabled()) {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
+ LOGGER.debug("{} end", getClass().getSimpleName());
+ }
return FizzPluginFilterChain.next(exchange);
}
}
diff --git a/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java b/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java
index e5ed774..c12a54f 100644
--- a/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java
+++ b/fizz-core/src/main/java/com/fizzgate/plugin/stat/StatPluginFilter.java
@@ -90,6 +90,7 @@ public class StatPluginFilter extends PluginFilter {
accessStat.reqTime = System.currentTimeMillis();
accessStat.reqs++;
if (LOGGER.isDebugEnabled()) {
+ org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, WebUtils.getTraceId(exchange));
LOGGER.debug("update access stat: {}, which request at {}", accessStat, DateTimeUtils.convert(accessStat.reqTime, Consts.DP.DP19));
}
}
diff --git a/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java b/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java
index a29fc01..a430b74 100644
--- a/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java
+++ b/fizz-core/src/main/java/com/fizzgate/proxy/FizzWebClient.java
@@ -220,7 +220,6 @@ public class FizzWebClient {
if (log.isDebugEnabled()) {
StringBuilder b = ThreadContext.getStringBuilder();
WebUtils.request2stringBuilder(traceId, method, uri, headers, null, b);
- // log.debug(b.toString(), LogService.BIZ_ID, traceId);
org.apache.logging.log4j.ThreadContext.put(Consts.TRACE_ID, traceId);
log.debug(b.toString());
}
@@ -243,10 +242,6 @@ public class FizzWebClient {
}
setHostHeader(uri, hdrs);
if (systemConfig.isFizzWebClientXForwardedForEnable()) {
- List values = hdrs.get(X_FORWARDED_FOR);
- /* if (CollectionUtils.isEmpty(values)) {
- hdrs.add(X_FORWARDED_FOR, WebUtils.getOriginIp(null));
- } */
if (systemConfig.isFizzWebClientXForwardedForAppendGatewayIp()) {
hdrs.add(X_FORWARDED_FOR, NetworkUtils.getServerIp());
}
@@ -269,8 +264,9 @@ public class FizzWebClient {
Mono cr = req.exchange();
if (timeout == 0) {
- if (systemConfig.getRouteTimeout() != 0) {
- timeout = systemConfig.getRouteTimeout();
+ long systemConfigRouteTimeout = systemConfig.getRouteTimeout();
+ if (systemConfigRouteTimeout != 0) {
+ timeout = systemConfigRouteTimeout;
}
}
if (timeout > 0) {
diff --git a/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java b/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java
index 16417ec..919177a 100644
--- a/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java
+++ b/fizz-core/src/main/java/com/fizzgate/stats/FlowStat.java
@@ -17,8 +17,20 @@
package com.fizzgate.stats;
-import java.util.*;
+import com.fizzgate.stats.circuitbreaker.CircuitBreakManager;
+import com.fizzgate.stats.circuitbreaker.CircuitBreaker;
+import com.fizzgate.util.Consts;
+import com.fizzgate.util.ResourceIdUtils;
+import com.fizzgate.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.server.ServerWebExchange;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
@@ -26,17 +38,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiFunction;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.server.ServerWebExchange;
-
-import com.fizzgate.stats.circuitbreaker.CircuitBreakManager;
-import com.fizzgate.stats.circuitbreaker.CircuitBreaker;
-import com.fizzgate.util.ResourceIdUtils;
-import com.fizzgate.util.WebUtils;
+import java.util.stream.Collectors;
/**
* Flow Statistic
@@ -524,7 +526,7 @@ public class FlowStat {
long slotInterval = slotIntervalInSec * 1000;
if (resourceId == null) {
- Set> entrys = resourceStats.entrySet();
+ Set> entrys = resourceStats.entrySet();
for (Entry entry : entrys) {
String rid = entry.getKey();
ResourceTimeWindowStat resourceWin = new ResourceTimeWindowStat(rid);
@@ -585,7 +587,7 @@ public class FlowStat {
}
}*/
for (long i = lastSlotId; i < slotId;) {
- Set> entrys = stat.resourceStats.entrySet();
+ Set> entrys = stat.resourceStats.entrySet();
for (Entry entry : entrys) {
String resourceId = entry.getKey();
ConcurrentMap timeSlots = entry.getValue().getTimeSlots();
@@ -649,7 +651,7 @@ public class FlowStat {
long curTimeSlotId = stat.currentTimeSlotId();
if (lastTimeSlotId == null || lastTimeSlotId.longValue() != curTimeSlotId) {
// log.debug("PeakConcurrentJob start");
- Set> entrys = stat.resourceStats.entrySet();
+ Set> entrys = stat.resourceStats.entrySet();
for (Entry entry : entrys) {
String resource = entry.getKey();
// log.debug("PeakConcurrentJob: resourceId={} slotId=={}", resourceId,
diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml
index 1c192eb..52ec30d 100644
--- a/fizz-plugin/pom.xml
+++ b/fizz-plugin/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.1
+ 2.7.2-SNAPSHOT
../pom.xml
4.0.0
diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml
index 6cae080..eecfae5 100644
--- a/fizz-spring-boot-starter/pom.xml
+++ b/fizz-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.1
+ 2.7.2-SNAPSHOT
../pom.xml
4.0.0
diff --git a/pom.xml b/pom.xml
index 142c19f..121ca24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
Dysprosium-SR25
5.3.7.RELEASE
2.2.7.RELEASE
- 4.1.89.Final
+ 4.1.90.Final
4.4.16
2.17.2
1.7.36
@@ -38,7 +38,7 @@
fizz-gateway-community
${project.artifactId}
fizz gateway community
- 2.7.1
+ 2.7.2-SNAPSHOT
pom
fizz-common
@@ -418,7 +418,7 @@
io.netty
- netty-tcnative
+ netty-tcnative-classes
${netty-tcnative.version}
@@ -428,7 +428,37 @@
io.netty
- netty-tcnative-classes
+ netty-tcnative-boringssl-static
+ ${netty-tcnative.version}
+ linux-x86_64
+
+
+ io.netty
+ netty-tcnative-boringssl-static
+ ${netty-tcnative.version}
+ linux-aarch_64
+
+
+ io.netty
+ netty-tcnative-boringssl-static
+ ${netty-tcnative.version}
+ osx-x86_64
+
+
+ io.netty
+ netty-tcnative-boringssl-static
+ ${netty-tcnative.version}
+ osx-aarch_64
+
+
+ io.netty
+ netty-tcnative-boringssl-static
+ ${netty-tcnative.version}
+ windows-x86_64
+
+
+ io.netty
+ netty-tcnative
${netty-tcnative.version}
From 97b4785485030ddf90b7fbf3e6c5d03dbe84f0b5 Mon Sep 17 00:00:00 2001
From: hongqiaowei
Date: Sat, 25 Mar 2023 11:03:18 +0800
Subject: [PATCH 5/8] Upgrade spring Framework to 5.2.23 to fix cve-2023-20861
---
fizz-bootstrap/pom.xml | 2 +-
pom.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml
index b95c7f0..1d22b7d 100644
--- a/fizz-bootstrap/pom.xml
+++ b/fizz-bootstrap/pom.xml
@@ -14,7 +14,7 @@
2.2.13.RELEASE
- 5.2.22.RELEASE
+ 5.2.23.RELEASE
Dysprosium-SR25
5.3.7.RELEASE
2.2.7.RELEASE
From c491f4a93c55fb3a332f876ef0f8f9a3458b2cab Mon Sep 17 00:00:00 2001
From: hongqiaowei
Date: Tue, 4 Apr 2023 14:33:22 +0800
Subject: [PATCH 6/8] Ip plugin
---
fizz-bootstrap/pom.xml | 2 +-
.../java/com/fizzgate/plugin/ip/IpPlugin.java | 148 ++++++++++
.../com/fizzgate/plugin/ip/PluginConfig.java | 18 ++
.../com/fizzgate/plugin/ip/RouterConfig.java | 19 ++
.../fizzgate/plugin/ip/util/ConfigUtils.java | 36 +++
.../fizzgate/plugin/ip/util/IpMatchUtils.java | 271 ++++++++++++++++++
.../com/fizzgate/plugin/ip/util/IpUtils.java | 191 ++++++++++++
pom.xml | 2 +-
8 files changed, 685 insertions(+), 2 deletions(-)
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java
create mode 100644 fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java
diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml
index 1d22b7d..9e1fb67 100644
--- a/fizz-bootstrap/pom.xml
+++ b/fizz-bootstrap/pom.xml
@@ -18,7 +18,7 @@
Dragonfruit-SR3
Dysprosium-SR25
5.3.7.RELEASE
- 4.1.90.Final
+ 4.1.91.Final
4.4.16
2.17.2
1.7.36
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java
new file mode 100644
index 0000000..1bb537d
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/IpPlugin.java
@@ -0,0 +1,148 @@
+package com.fizzgate.plugin.ip;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fizzgate.plugin.ip.util.ConfigUtils;
+import com.fizzgate.plugin.ip.util.IpMatchUtils;
+import com.fizzgate.plugin.ip.util.IpUtils;
+import com.fizzgate.plugin.FizzPluginFilter;
+import com.fizzgate.plugin.FizzPluginFilterChain;
+import com.fizzgate.plugin.auth.ApiConfig;
+import com.fizzgate.plugin.auth.ApiConfigService;
+import com.fizzgate.util.WebUtils;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Resource;
+import java.net.SocketException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static com.fizzgate.plugin.ip.RouterConfig.FieldName.*;
+
+/**
+ * @author hua.huang
+ */
+@Slf4j
+@Component(value = IpPlugin.PLUGIN_NAME)
+public class IpPlugin implements FizzPluginFilter {
+ public static final String PLUGIN_NAME = "fizz_plugin_ip";
+ @Resource
+ private ObjectMapper objectMapper;
+ @Resource
+ private ApiConfigService apiConfigService;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Mono filter(ServerWebExchange exchange, Map config) {
+ RouterConfig routerConfig = routerConfig(exchange, config);
+ List pluginConfigItemList = null;/* pluginConfig(exchange, config); */
+ if (access(exchange, routerConfig, pluginConfigItemList)) {
+ log.trace("pass...");
+ return FizzPluginFilterChain.next(exchange);
+ }
+ log.trace("forbidden!");
+ HttpHeaders headers = new HttpHeaders();
+ headers.set(HttpHeaders.CONTENT_TYPE, routerConfig.getErrorRespContentType());
+ return WebUtils.buildDirectResponse(exchange, HttpStatus.FORBIDDEN,
+ headers, routerConfig.getErrorRespContent());
+ }
+
+ private boolean access(ServerWebExchange exchange,
+ RouterConfig routerConfig, List pluginConfigItemList) {
+ Set fixedWhiteIpSet = Sets.newHashSet();
+ Set fixedBlackIpSet = Sets.newHashSet();
+ ApiConfig apiConfig = apiConfig(exchange);
+ Set gatewayGroups = (apiConfig == null || apiConfig.gatewayGroups == null) ? Sets.newHashSet() : apiConfig.gatewayGroups;
+ /* if (!CollectionUtils.isEmpty(pluginConfigItemList)) {
+ for (PluginConfig.Item fixedConfigItem : pluginConfigItemList) {
+ if (gatewayGroups.contains(fixedConfigItem.getGwGroup())) {
+ fixedWhiteIpSet.addAll(IpMatchUtils.ipConfigList(fixedConfigItem.getWhiteIp()));
+ fixedBlackIpSet.addAll(IpMatchUtils.ipConfigList(fixedConfigItem.getBlackIp()));
+ }
+ }
+ } */
+ Set whiteIpSet = ConfigUtils.string2set(routerConfig.getWhiteIp());
+ Set blackIpSet = ConfigUtils.string2set(routerConfig.getBlackIp());
+
+ String ip = null;
+ try {
+ ip = IpUtils.getServerHttpRequestIp(exchange.getRequest());
+ } catch (SocketException e) {
+ log.warn(e.getMessage(), e);
+ }
+ log.trace("clientIp:{}, fixedWhiteIpSet:{}, fixedBlackIpSet:{}, whiteIpSet:{}, blackIpSet:{}",
+ ip, fixedWhiteIpSet, fixedBlackIpSet, whiteIpSet, blackIpSet);
+ // 未获取到client ip,返回false
+ if (StringUtils.isBlank(ip)) {
+ return false;
+ }
+
+ // 优先匹配路由级别配置,然后再匹配插件级别配置
+
+ // 路由级别::白名单匹配到就直接返回true
+ if (IpMatchUtils.match(ip, whiteIpSet)) {
+ return true;
+ }
+ // 路由级别::黑名单匹配到就直接返回false
+ if (IpMatchUtils.match(ip, blackIpSet)) {
+ return false;
+ }
+ // 插件级别::白名单匹配到就直接返回true
+ /* if (IpMatchUtils.match(ip, fixedWhiteIpSet)) {
+ return true;
+ } */
+ // 插件级别::黑名单匹配到就直接返回false
+ /* if (IpMatchUtils.match(ip, fixedBlackIpSet)) {
+ return false;
+ } */
+ // 路由级别和插件级别都没匹配到
+ if (CollectionUtils.isEmpty(whiteIpSet) /* || CollectionUtils.isEmpty(fixedWhiteIpSet) */) {
+ // 都没有配置白名单,默认返回true
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private RouterConfig routerConfig(ServerWebExchange exchange, Map config) {
+ RouterConfig routerConfig = new RouterConfig();
+ routerConfig.setErrorRespContentType((String) config.getOrDefault(ERROR_RESP_CONTENT_TYPE
+ , routerConfig.getErrorRespContentType()));
+ routerConfig.setErrorRespContent((String) config.getOrDefault(ERROR_RESP_CONTENT
+ , routerConfig.getErrorRespContent()));
+ routerConfig.setWhiteIp((String) config.getOrDefault(WHITE_IP, StringUtils.EMPTY));
+ routerConfig.setBlackIp((String) config.getOrDefault(BLACK_IP, StringUtils.EMPTY));
+ return routerConfig;
+ }
+
+ private List pluginConfig(ServerWebExchange exchange, Map config) {
+ String fixedConfig = (String) config.get(com.fizzgate.plugin.PluginConfig.CUSTOM_CONFIG);
+ try {
+ PluginConfig pluginConfig = objectMapper.readValue(fixedConfig, PluginConfig.class);
+ if (pluginConfig != null && pluginConfig.getConfigs() != null) {
+ return pluginConfig.getConfigs();
+ }
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ return Lists.newArrayList();
+ }
+
+ private ApiConfig apiConfig(ServerWebExchange exchange) {
+ ServerHttpRequest req = exchange.getRequest();
+ return apiConfigService.getApiConfig(WebUtils.getAppId(exchange),
+ WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange));
+ }
+
+}
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java
new file mode 100644
index 0000000..c642c19
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/PluginConfig.java
@@ -0,0 +1,18 @@
+package com.fizzgate.plugin.ip;
+
+import com.google.common.collect.Lists;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PluginConfig {
+ private List- configs = Lists.newArrayList();
+
+ @Data
+ public static class Item {
+ private String gwGroup;
+ private String whiteIp;
+ private String blackIp;
+ }
+}
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java
new file mode 100644
index 0000000..9db1741
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/RouterConfig.java
@@ -0,0 +1,19 @@
+package com.fizzgate.plugin.ip;
+
+import lombok.Data;
+import org.springframework.http.MediaType;
+
+@Data
+public class RouterConfig {
+ private String errorRespContentType = MediaType.APPLICATION_JSON_UTF8_VALUE;
+ private String errorRespContent = "{\"msg\":\"非法IP\",\"code\":-1}";
+ private String whiteIp;
+ private String blackIp;
+
+ public interface FieldName {
+ String ERROR_RESP_CONTENT_TYPE = "errorRespContentType";
+ String ERROR_RESP_CONTENT = "errorRespContent";
+ String WHITE_IP = "whiteIp";
+ String BLACK_IP = "blackIp";
+ }
+}
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java
new file mode 100644
index 0000000..a29d03a
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/ConfigUtils.java
@@ -0,0 +1,36 @@
+package com.fizzgate.plugin.ip.util;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public abstract class ConfigUtils {
+ public static final String DEFAULT_CHAR_MATCHER_ANY_OF = ",\n";
+
+ public static Set string2set(String strVal, String charMatcherAnyOf) {
+ Set finalSet = Sets.newHashSet();
+ if (StringUtils.isBlank(strVal)) {
+ return finalSet;
+ }
+ charMatcherAnyOf = StringUtils.isBlank(charMatcherAnyOf) ? DEFAULT_CHAR_MATCHER_ANY_OF : charMatcherAnyOf;
+ Set set = Sets.newHashSet(
+ Splitter.on(CharMatcher.anyOf(charMatcherAnyOf)).trimResults().split(strVal));
+ set = set.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet());
+ for (String s : set) {
+ if (StringUtils.isBlank(s)) {
+ continue;
+ }
+ finalSet.add(StringUtils.trimToEmpty(s));
+ }
+ return finalSet;
+ }
+
+ public static Set string2set(String strVal) {
+ return string2set(strVal, DEFAULT_CHAR_MATCHER_ANY_OF);
+ }
+
+}
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java
new file mode 100644
index 0000000..70124b6
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpMatchUtils.java
@@ -0,0 +1,271 @@
+package com.fizzgate.plugin.ip.util;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Sets;
+import inet.ipaddr.AddressStringException;
+import inet.ipaddr.IPAddress;
+import inet.ipaddr.IPAddressString;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * ipv4匹配工具
+ */
+public final class IpMatchUtils {
+ // IP正则
+ private static final Pattern IP_PATTERN = Pattern.compile(
+ "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\."
+ + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})\\." + "(1\\d{1,2}|2[0-4]\\d|25[0-5]|\\d{1,2})");
+ public static final String DEFAULT_ALLOW_ALL_FLAG = "*";// 允许所有ip标志位
+ public static final String DEFAULT_DENY_ALL_FLAG = "0"; // 禁止所有ip标志位
+ private static final String RANGE_SPLITTER = "-"; // ip范围分隔符
+
+ /**
+ * 根据IP白名单设置获取可用的IP列表
+ */
+ public static Set ipConfigList(String allowIp) {
+ // 拆分出白名单正则
+ Set set = Sets.newHashSet(Splitter.on(CharMatcher.anyOf(",\n")).trimResults().split(allowIp));
+ set = set.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet());
+ return ipConfigList(Sets.newHashSet(set));
+ }
+
+ /**
+ * 根据IP白名单设置获取可用的IP列表
+ */
+ public static Set ipConfigList(Set allowIpList) {
+ Set ipList = new HashSet<>(allowIpList.size());
+ for (String allow : allowIpList) {
+ if (allow.contains("*")) { // 处理通配符 *
+ String[] ips = allow.split("\\.");
+ String[] from = new String[]{"0", "0", "0", "0"};
+ String[] end = new String[]{"255", "255", "255", "255"};
+ List tem = new ArrayList<>();
+ for (int i = 0; i < ips.length; i++)
+ if (ips[i].contains("*")) {
+ tem = complete(ips[i]);
+ from[i] = null;
+ end[i] = null;
+ } else {
+ from[i] = ips[i];
+ end[i] = ips[i];
+ }
+
+ StringBuilder fromIP = new StringBuilder();
+ StringBuilder endIP = new StringBuilder();
+ for (int i = 0; i < 4; i++) {
+ if (from[i] != null) {
+ fromIP.append(from[i]).append(".");
+ endIP.append(end[i]).append(".");
+ } else {
+ fromIP.append("[*].");
+ endIP.append("[*].");
+ }
+ }
+ fromIP.deleteCharAt(fromIP.length() - 1);
+ endIP.deleteCharAt(endIP.length() - 1);
+
+ for (String s : tem) {
+ String ip = fromIP.toString().replace("[*]", s.split(";")[0]) + RANGE_SPLITTER
+ + endIP.toString().replace("[*]", s.split(";")[1]);
+ if (validate(ip)) {
+ ipList.add(ip);
+ }
+ }
+ } else if (allow.contains("/")) { // 处理 网段 xxx.xxx.xxx./24
+ ipList.add(allow);
+ } else { // 处理单个 ip 或者 范围
+ if (validate(allow)) {
+ ipList.add(allow);
+ }
+ }
+
+ }
+
+ return ipList;
+ }
+
+ /**
+ * 对单个IP节点进行范围限定
+ *
+ * @param arg
+ * @return 返回限定后的IP范围,格式为List[10;19, 100;199]
+ */
+ private static List complete(String arg) {
+ List com = new ArrayList<>();
+ int len = arg.length();
+ if (len == 1) {
+ com.add("0;255");
+ } else if (len == 2) {
+ String s1 = complete(arg, 1);
+ if (s1 != null) {
+ com.add(s1);
+ }
+ String s2 = complete(arg, 2);
+ if (s2 != null) {
+ com.add(s2);
+ }
+ } else {
+ String s1 = complete(arg, 1);
+ if (s1 != null) {
+ com.add(s1);
+ }
+ }
+ return com;
+ }
+
+ private static String complete(String arg, int length) {
+ String from = "";
+ String end = "";
+ if (length == 1) {
+ from = arg.replace("*", "0");
+ end = arg.replace("*", "9");
+ } else {
+ from = arg.replace("*", "00");
+ end = arg.replace("*", "99");
+ }
+ if (Integer.parseInt(from) > 255) {
+ return null;
+ }
+ if (Integer.parseInt(end) > 255) {
+ end = "255";
+ }
+ return from + ";" + end;
+ }
+
+ /**
+ * 在添加至白名单时进行格式校验
+ */
+ private static boolean validate(String ip) {
+ String[] temp = ip.split(RANGE_SPLITTER);
+ for (String s : temp) {
+ if (!IP_PATTERN.matcher(s).matches()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 根据IP,及可用Ip列表来判断ip是否包含在白名单之中
+ */
+ public static boolean match(String ip, Set ipList) {
+ if (CollectionUtils.isEmpty(ipList)) {
+ return false;
+ }
+ if (ipList.contains(ip)) {
+ return true;
+ }
+ IPAddress ipAddress = null;
+ try {
+ ipAddress = new IPAddressString(ip).toAddress();
+ } catch (AddressStringException e) {
+ throw new RuntimeException(e);
+ }
+ for (String allow : ipList) {
+ if (allow.contains(RANGE_SPLITTER)) { // 处理 类似 192.168.0.0-192.168.2.1
+ String[] tempAllow = allow.split(RANGE_SPLITTER);
+ String[] from = tempAllow[0].split("\\.");
+ String[] end = tempAllow[1].split("\\.");
+ String[] tag = ip.split("\\.");
+ boolean check = true;
+ for (int i = 0; i < 4; i++) { // 对IP从左到右进行逐段匹配
+ int s = Integer.parseInt(from[i]);
+ int t = Integer.parseInt(tag[i]);
+ int e = Integer.parseInt(end[i]);
+ if (!(s <= t && t <= e)) {
+ check = false;
+ break;
+ }
+ }
+ if (check) {
+ return true;
+ }
+ } else if (allow.contains("/")) { // 处理 网段 xxx.xxx.xxx./24
+ int splitIndex = allow.indexOf("/");
+ // 取出子网段
+ String ipSegment = allow.substring(0, splitIndex); // 192.168.3.0
+ // 子网数
+ String netmask = allow.substring(splitIndex + 1); // 24
+ // ip 转二进制
+ long ipLong = ipToLong(ip);
+ // 子网二进制
+ long maskLong = (2L << 32 - 1) - (2L << (32 - Integer.parseInt(netmask)) - 1);
+ // ip与和子网相与 得到 网络地址
+ String calcSegment = longToIP(ipLong & maskLong);
+ // 如果计算得出网络地址和库中网络地址相同 则合法
+ if (ipSegment.equals(calcSegment)) {
+ return true;
+ }
+ } else if (allow.contains("*")) {
+ IPAddress rangeAddress = new IPAddressString(allow).getAddress();
+ if (rangeAddress.contains(ipAddress)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 根据IP地址,及IP白名单设置规则判断IP是否包含在白名单
+ */
+ public static boolean match(String ip, String ipWhiteConfig) {
+ if (null == ip || "".equals(ip)) {
+ return false;
+ }
+ // ip格式不对
+ if (!IP_PATTERN.matcher(ip).matches()) {
+ return false;
+ }
+ if (DEFAULT_ALLOW_ALL_FLAG.equals(ipWhiteConfig)) {
+ return true;
+ }
+ if (DEFAULT_DENY_ALL_FLAG.equals(ipWhiteConfig)) {
+ return false;
+ }
+ Set ipList = ipConfigList(ipWhiteConfig);
+ return match(ip, ipList);
+ }
+
+ /**
+ * 将 127.0.0.1形式的IP地址 转换成 10进制整数形式
+ */
+ private static long ipToLong(String strIP) {
+ long[] ip = new long[4];
+ // 先找到IP地址字符串中.的位置
+ int position1 = strIP.indexOf(".");
+ int position2 = strIP.indexOf(".", position1 + 1);
+ int position3 = strIP.indexOf(".", position2 + 1);
+ // 将每个.之间的字符串转换成整型
+ ip[0] = Long.parseLong(strIP.substring(0, position1));
+ ip[1] = Long.parseLong(strIP.substring(position1 + 1, position2));
+ ip[2] = Long.parseLong(strIP.substring(position2 + 1, position3));
+ ip[3] = Long.parseLong(strIP.substring(position3 + 1));
+ return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
+ }
+
+ /**
+ * 将 10进制整数形式 转换成 127.0.0.1形式的IP地址
+ */
+ private static String longToIP(long longIP) {
+ // 直接右移24位
+ return "" + (longIP >>> 24) +
+ "." +
+ // 将高8位置0,然后右移16位
+ ((longIP & 0x00FFFFFF) >>> 16) +
+ "." +
+ ((longIP & 0x0000FFFF) >>> 8) +
+ "." +
+ (longIP & 0x000000FF);
+ }
+
+}
\ No newline at end of file
diff --git a/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java
new file mode 100644
index 0000000..64917c7
--- /dev/null
+++ b/fizz-plugin/src/main/java/com/fizzgate/plugin/ip/util/IpUtils.java
@@ -0,0 +1,191 @@
+package com.fizzgate.plugin.ip.util;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+import java.net.*;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author huahua
+ */
+public class IpUtils {
+
+ /*
+ * 取所有IP段的私有IP段
+ * A类 私有地址 10.0.0.0---10.255.255.255 保留地址 127.0.0.0---127.255.255.255
+ * B类 私有地址 172.16.0.0-172.31.255.255
+ * C类 私有地址 192.168.0.0-192.168.255.255
+ * D类 地址不分网络地址和主机地址
+ * E类 地址不分网络地址和主机地址
+ */
+ private static long
+ aBegin = ipToLong("10.0.0.0"),
+ aEnd = ipToLong("10.255.255.255"),
+ bBegin = ipToLong("172.16.0.0"),
+ bEnd = ipToLong("172.31.255.255"),
+ cBegin = ipToLong("192.168.0.0"),
+ cEnd = ipToLong("192.168.255.255"),
+ saveBegin = ipToLong("127.0.0.0"),
+ saveEnd = ipToLong("127.255.255.255");
+
+ // 跟IP有关需要做判断的header参数
+ private static String
+ CLIENT_IP = "clientip",
+ X_FORWARDED_FOR = "x-forwarded-for",
+ PROXY_CLIENT_IP = "proxy-client-ip",
+ WL_PROXY_CLIENT_IP = "wl-proxy-client-ip";
+ private static Set ipHeaderNames = Sets.newHashSet(CLIENT_IP, X_FORWARDED_FOR, PROXY_CLIENT_IP, WL_PROXY_CLIENT_IP);
+
+ public static String getServerHttpRequestIp(ServerHttpRequest request) throws SocketException {
+ // 防止在header中的参数名有大小写之分,重新将需要处理的参数值和内容装填入Map中
+ Map> ipHeaders = Maps.newHashMap();
+ Set>> headers = request.getHeaders().entrySet();
+ for (Map.Entry> header : headers) {
+ String name = header.getKey();
+ String lowerCaseName = name.toLowerCase();
+ if (ipHeaderNames.contains(lowerCaseName)) {
+ List values = Lists.newArrayList();
+ for (String headerValue : header.getValue()) {
+ if (StringUtils.indexOf(headerValue, ",") >= 0) {
+ String[] headerValueArr = StringUtils.split(headerValue, ",");
+ if (headerValueArr.length > 0) {
+ for (String s : headerValueArr) {
+ values.add(StringUtils.trimToEmpty(s));
+ }
+ }
+ } else {
+ values.add(headerValue);
+ }
+ }
+ ipHeaders.put(lowerCaseName, values); // 装填key和value
+ }
+ }
+ //取正确的IP
+ String ipAddress = null;
+ // 取clientip
+ List clientIpList = ipHeaders.get(CLIENT_IP); // 取clientip与client-ip有区别
+ ipAddress = fetchPublicIp(clientIpList);
+ // 若clientip为空或者是内网IP则取x-forwarded-for
+ if (StringUtils.isBlank(ipAddress)) {
+ List xForwardedIpList = ipHeaders.get(X_FORWARDED_FOR);
+ ipAddress = fetchPublicIp(xForwardedIpList);
+ }
+ // 若x-forwarded-for为空则取proxy-client-ip
+ if (StringUtils.isBlank(ipAddress)) {
+ List proxyClientIpList = ipHeaders.get(PROXY_CLIENT_IP);
+ ipAddress = fetchPublicIp(proxyClientIpList);
+ }
+ // 若proxy-client-ip为空则取wl-proxy-client-ip
+ if (StringUtils.isBlank(ipAddress)) {
+ List wlProxyClientIpList = ipHeaders.get(WL_PROXY_CLIENT_IP);
+ ipAddress = fetchPublicIp(wlProxyClientIpList);
+ }
+ // 若wl-proxy-client-ip为空则取RemoteAddr
+ if (StringUtils.isBlank(ipAddress)) {
+ InetSocketAddress inetSocketAddress = request.getRemoteAddress();
+ if (inetSocketAddress != null) {
+ InetAddress inetAddress = inetSocketAddress.getAddress();
+ if (inetAddress instanceof Inet4Address) {
+ ipAddress = inetAddress.getHostAddress();
+ }
+ }
+ if (StringUtils.equals(ipAddress, "127.0.0.1")) {
+ // 根据网卡取本机配置的IP
+ ipAddress = getLocalIp();
+ }
+ }
+ return ipAddress;
+ }
+
+ public static String getLocalIp() throws SocketException {
+ Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces();
+ InetAddress ip;
+ while (allNetInterfaces.hasMoreElements()) {
+ NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
+ Enumeration addresses = netInterface.getInetAddresses();
+ while (addresses.hasMoreElements()) {
+ ip = (InetAddress) addresses.nextElement();
+ if (ip instanceof Inet4Address) {
+ return ip.getHostAddress();
+ }
+ }
+ }
+ return "";
+ }
+
+ public static long localIpNumber() throws SocketException {
+ return ipToLong(getLocalIp());
+ }
+
+ private static long ipToLong(String ipAddress) {
+ long result = 0L;
+ String[] ipAddressInArray = ipAddress.split("\\.");
+ if (ipAddressInArray.length != 4) {
+ return 0;
+ }
+ for (int i = 3; i >= 0; i--) {
+ long ip = 0;
+ try {
+ ip = Long.parseLong(ipAddressInArray[3 - i]);
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ result |= ip << (i * 8);
+ }
+ return result;
+ }
+
+ public static String fetchPublicIp(List ipAddressList) {
+ String ipAddress = null;
+ if (ipAddressList == null || ipAddressList.size() <= 0) {
+ return ipAddress;
+ }
+ for (String ip : ipAddressList) {
+ long ipNum = ipToLong(ip);
+ if (isIpAddress(ip)
+ && !isInner(ipNum, aBegin, aEnd)
+ && !isInner(ipNum, bBegin, bEnd)
+ && !isInner(ipNum, cBegin, cEnd)
+ && !isInner(ipNum, saveBegin, saveEnd)) {
+ ipAddress = ip;
+ break;
+ }
+ }
+ return ipAddress;
+ }
+
+ public static boolean isInnerIP(String ipAddress) {
+ long ipNum = ipToLong(ipAddress);
+ return isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || isInner(ipNum, saveBegin, saveEnd);
+ }
+
+ private static boolean isInner(long userIp, long begin, long end) {
+ return (userIp >= begin) && (userIp <= end);
+ }
+
+ /**
+ * 检验是否是合法的IP地址
+ *
+ * @param address String IP地址
+ * @return boolean IP地址是否合法
+ */
+ public static boolean isIpAddress(String address) {
+ if (StringUtils.isEmpty(address)) {
+ return false;
+ }
+ String regex = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";
+ Pattern p = Pattern.compile(regex);
+ Matcher m = p.matcher(address);
+ return m.matches();
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index a6e3601..5309cc0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
Dysprosium-SR25
5.3.7.RELEASE
2.2.7.RELEASE
- 4.1.90.Final
+ 4.1.91.Final
4.4.16
2.17.2
1.7.36
From 96bfe4defcfbf4be3498d5dbff1874c25cce30f7 Mon Sep 17 00:00:00 2001
From: Francis Dong
Date: Mon, 10 Apr 2023 17:54:01 +0800
Subject: [PATCH 7/8] correct comment
---
fizz-bootstrap/js/common.js | 4 ++--
fizz-bootstrap/src/main/resources/js/common.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fizz-bootstrap/js/common.js b/fizz-bootstrap/js/common.js
index cccb334..c8eb437 100644
--- a/fizz-bootstrap/js/common.js
+++ b/fizz-bootstrap/js/common.js
@@ -166,11 +166,11 @@ var common = {
},
/**
- * 获取步骤中调用的接口的响应头
+ * 获取步骤中调用的接口的响应体
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步骤名【必填】
* @param {*} requestName 请求的接口名 【必填】
- * @param {*} field 字段名 【选填】,不传时返回整个响应头
+ * @param {*} field 字段名 【选填】,不传时返回整个响应体
*/
getStepRespBody: function (ctx, stepName, requestName, field){
var resp = this.getStepResp(ctx, stepName, requestName);
diff --git a/fizz-bootstrap/src/main/resources/js/common.js b/fizz-bootstrap/src/main/resources/js/common.js
index cccb334..c8eb437 100644
--- a/fizz-bootstrap/src/main/resources/js/common.js
+++ b/fizz-bootstrap/src/main/resources/js/common.js
@@ -166,11 +166,11 @@ var common = {
},
/**
- * 获取步骤中调用的接口的响应头
+ * 获取步骤中调用的接口的响应体
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步骤名【必填】
* @param {*} requestName 请求的接口名 【必填】
- * @param {*} field 字段名 【选填】,不传时返回整个响应头
+ * @param {*} field 字段名 【选填】,不传时返回整个响应体
*/
getStepRespBody: function (ctx, stepName, requestName, field){
var resp = this.getStepResp(ctx, stepName, requestName);
From 15036163eda395e3257cf9730b54fa16d8f4a3c8 Mon Sep 17 00:00:00 2001
From: hongqiaowei
Date: Mon, 10 Apr 2023 18:08:58 +0800
Subject: [PATCH 8/8] Release 2.7.2
---
README.en-us.md | 3 ++-
README.md | 3 ++-
docker-compose.yml | 6 +++---
fizz-bootstrap/pom.xml | 2 +-
fizz-common/pom.xml | 2 +-
fizz-core/pom.xml | 2 +-
fizz-plugin/pom.xml | 2 +-
fizz-spring-boot-starter/pom.xml | 2 +-
pom.xml | 2 +-
9 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/README.en-us.md b/README.en-us.md
index c0f2707..5c7de49 100644
--- a/README.en-us.md
+++ b/README.en-us.md
@@ -4,7 +4,7 @@ English | [简体中文](./README.md)
-
+
@@ -107,6 +107,7 @@ Starting from v1.3.0, the frontend and backend of the management backend are mer
| v2.6.6 | v2.6.6 |
| v2.7.0 | v2.7.0 |
| v2.7.1 | v2.7.1 |
+| v2.7.2 | v2.7.2 |
Please download the corresponding management backend version according to the version of the community version
diff --git a/README.md b/README.md
index 7c34a62..539f8cc 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
-
+
@@ -109,6 +109,7 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
| v2.6.6 | v2.6.6 |
| v2.7.0 | v2.7.0 |
| v2.7.1 | v2.7.1 |
+| v2.7.2 | v2.7.2 |
请根据社区版的版本下载对应的管理后台版本
diff --git a/docker-compose.yml b/docker-compose.yml
index 77d39ae..3436910 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,7 +2,7 @@ version: "3.6"
services:
fizz-mysql:
- image: "fizzgate/fizz-mysql:2.7.1"
+ image: "fizzgate/fizz-mysql:2.7.2"
container_name: fizz-mysql
restart: always
hostname: fizz-mysql
@@ -27,7 +27,7 @@ services:
- fizz
fizz-gateway-community:
- image: "fizzgate/fizz-gateway-community:2.7.1"
+ image: "fizzgate/fizz-gateway-community:2.7.2"
container_name: fizz-gateway-community
restart: always
hostname: fizz-gateway-community
@@ -48,7 +48,7 @@ services:
- fizz
fizz-manager-professional:
- image: "fizzgate/fizz-manager-professional:2.7.1"
+ image: "fizzgate/fizz-manager-professional:2.7.2"
container_name: fizz-manager-professional
restart: always
hostname: fizz-manager-professional
diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml
index 9e1fb67..7e46f76 100644
--- a/fizz-bootstrap/pom.xml
+++ b/fizz-bootstrap/pom.xml
@@ -6,7 +6,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.2-SNAPSHOT
+ 2.7.2
../pom.xml
diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml
index e3e6140..b109203 100644
--- a/fizz-common/pom.xml
+++ b/fizz-common/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.2-SNAPSHOT
+ 2.7.2
../pom.xml
4.0.0
diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml
index 4f67eed..d35ef94 100644
--- a/fizz-core/pom.xml
+++ b/fizz-core/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.2-SNAPSHOT
+ 2.7.2
../pom.xml
4.0.0
diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml
index 52ec30d..c07b832 100644
--- a/fizz-plugin/pom.xml
+++ b/fizz-plugin/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.2-SNAPSHOT
+ 2.7.2
../pom.xml
4.0.0
diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml
index eecfae5..a73333b 100644
--- a/fizz-spring-boot-starter/pom.xml
+++ b/fizz-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
fizz-gateway-community
com.fizzgate
- 2.7.2-SNAPSHOT
+ 2.7.2
../pom.xml
4.0.0
diff --git a/pom.xml b/pom.xml
index 5309cc0..c1a0cd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,7 +38,7 @@
fizz-gateway-community
${project.artifactId}
fizz gateway community
- 2.7.2-SNAPSHOT
+ 2.7.2
pom
fizz-common