Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update sentinel-spring-webmvc-v6x-adapter #3355

Open
wants to merge 11 commits into
base: 1.8
Choose a base branch
from
9 changes: 3 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ jobs:
- name: Setup Java for test
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
java-version: "${{ matrix.java }}"
distribution: 'temurin'
cache: 'maven'

- name: Setup Java for mvn
uses: actions/setup-java@v4
with:
java-version: 17
java-version: "17"
distribution: 'temurin'

- name: Maven Test With Spring 6.x
Expand All @@ -43,11 +43,8 @@ jobs:
run: mvn --batch-mode test -Dsurefire.jdk-toolchain-version=${{ matrix.java }} -Dskip.spring.v6x.test=true
if: ${{ matrix.java < 17 }}

- name: Build with Maven
run: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -DminimumPriority=1

- name: Upload coverage reports to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: alibaba/Sentinel

10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@
<artifactId>sentinel-extension</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dynamic-setting-extension</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-webflow-extension</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
Expand Down
9 changes: 8 additions & 1 deletion sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
Expand All @@ -81,6 +80,14 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-webflow-extension</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dynamic-setting-extension</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,28 @@
*/
package com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x;

import com.alibaba.csp.sentinel.*;
import com.alibaba.csp.sentinel.webflow.param.WebParamParser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.ResourceTypeConstants;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.config.BaseWebMvcConfig;
import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.param.HttpServletRequestItemParser;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.util.Map;

/**
* Since request may be reprocessed in flow if any forwarding or including or other action
* happened (see {@link jakarta.servlet.ServletRequest#getDispatcherType()}) we will only
Expand All @@ -52,10 +62,18 @@

private final BaseWebMvcConfig baseWebMvcConfig;

protected final WebParamParser<HttpServletRequest> webParamParser;

public AbstractSentinelInterceptor(BaseWebMvcConfig config) {
this(config, new WebParamParser<HttpServletRequest>(new HttpServletRequestItemParser()));
}

public AbstractSentinelInterceptor(BaseWebMvcConfig config, WebParamParser<HttpServletRequest> webParamParser) {
AssertUtil.notNull(config, "BaseWebMvcConfig should not be null");
AssertUtil.assertNotBlank(config.getRequestAttributeName(), "requestAttributeName should not be blank");
AssertUtil.assertNotNull(webParamParser, "webParamParser should not be null");
this.baseWebMvcConfig = config;
this.webParamParser = webParamParser;
}

/**
Expand All @@ -80,20 +98,25 @@
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String resourceName = "";
String resourceName = getResourceName(request);
if (StringUtil.isEmpty(resourceName)) {
return true;

Check warning on line 103 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/AbstractSentinelInterceptor.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/AbstractSentinelInterceptor.java#L103

Added line #L103 was not covered by tests
}
if (increaseReference(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) {
return true;

Check warning on line 106 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/AbstractSentinelInterceptor.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/AbstractSentinelInterceptor.java#L106

Added line #L106 was not covered by tests
}
try {
resourceName = getResourceName(request);
if (StringUtil.isEmpty(resourceName)) {
return true;
}
if (increaseReference(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) {
return true;
}
// Parse the request origin using registered origin parser.
String origin = parseOrigin(request);
String contextName = getContextName(request);
ContextUtil.enter(contextName, origin);
Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);

// Map<String, Object> params = webParamParser.parseParameterFor(resourceName, request, null);

// Note that AsyncEntry is REQUIRED here (for async Servlet scenarios).
// TODO: identify whether request is actually ASYNC here.
Entry entry = SphU.asyncEntry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);

request.setAttribute(baseWebMvcConfig.getRequestAttributeName(), entry);
return true;
} catch (BlockException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ protected String getResourceName(HttpServletRequest request) {
}
return resourceName;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@
*/
package com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback;

import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.config.WebServletLocalConfig;
import com.alibaba.csp.sentinel.setting.adapter.AdapterSettingManager;
import com.alibaba.csp.sentinel.setting.fallback.BlockFallbackConfig.WebBlockFallbackBehavior;
import com.alibaba.csp.sentinel.setting.fallback.BlockFallbackUtils;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.StringUtil;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

import static com.alibaba.csp.sentinel.setting.SentinelAdapterConstants.WEB_FALLBACK_CONTENT_TYPE_JSON;
import static com.alibaba.csp.sentinel.setting.SentinelAdapterConstants.WEB_FALLBACK_CONTENT_TYPE_TEXT;

/**
* Default handler for the blocked request.
*
Expand All @@ -30,13 +40,82 @@

@Override
public void handle(HttpServletRequest request, HttpServletResponse response, String resourceName, BlockException ex)
throws Exception {
// Return 429 (Too Many Requests) by default.
response.setStatus(429);
throws Exception {
StringBuffer url = request.getRequestURL();

if ("GET".equals(request.getMethod()) && StringUtil.isNotBlank(request.getQueryString())) {
url.append("?").append(request.getQueryString());
}

WebBlockFallbackBehavior b = BlockFallbackUtils.getFallbackBehavior(resourceName, ex);
if (b != null) {
writeBlockPageWith(response, b);
} else {
if (StringUtil.isBlank(WebServletLocalConfig.getBlockPage())) {
writeBlockPage(response, WebServletLocalConfig.getBlockPageHttpStatus());
} else {
String redirectUrl = WebServletLocalConfig.getBlockPage() + "?http_referer=" + url.toString();
// Redirect to the customized block page.
response.sendRedirect(redirectUrl);
}
}
}

private void writeBlockPageWith(HttpServletResponse response, WebBlockFallbackBehavior b) throws IOException {
int status = 429;
if (b.getWebRespStatusCode() != null && b.getWebRespStatusCode() > 0) {
status = b.getWebRespStatusCode();
}

Integer contentType = b.getWebRespContentType();
if (contentType != null && contentType == WEB_FALLBACK_CONTENT_TYPE_JSON) {
setContentTypeToJson(response);
}
if (contentType != null && contentType == WEB_FALLBACK_CONTENT_TYPE_TEXT) {
setContentTypeToText(response);
}
response.setStatus(status);
setCharsetToUtf8(response);
PrintWriter out = response.getWriter();
out.print(b.getWebRespMessage());
out.flush();
out.close();
}

private void writeBlockPage(HttpServletResponse response, int httpStatus) throws IOException {
response.setStatus(httpStatus);
setCharsetToUtf8(response);

Integer contentType = AdapterSettingManager.getWebRespContentType();
if (contentType != null && contentType.equals(WEB_FALLBACK_CONTENT_TYPE_JSON)) {
setContentTypeToJson(response);

Check warning on line 91 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/callback/DefaultBlockExceptionHandler.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/callback/DefaultBlockExceptionHandler.java#L91

Added line #L91 was not covered by tests
}
if (contentType != null && contentType == WEB_FALLBACK_CONTENT_TYPE_TEXT) {
setContentTypeToText(response);

Check warning on line 94 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/callback/DefaultBlockExceptionHandler.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/callback/DefaultBlockExceptionHandler.java#L94

Added line #L94 was not covered by tests
}
String respMessage = valueOrDefault(AdapterSettingManager.getWebRespMessage(), DEFAULT_BLOCK_MSG);

PrintWriter out = response.getWriter();
out.print("Blocked by Sentinel (flow limiting)");
out.print(respMessage);
out.flush();
out.close();
}

private static void setContentTypeToJson(HttpServletResponse response) {
response.setContentType("application/json");
}

private static void setContentTypeToText(HttpServletResponse response) {
response.setContentType("text/plain");
}

private static void setCharsetToUtf8(HttpServletResponse response) {
response.setCharacterEncoding("utf-8");
}

private static <R> R valueOrDefault(R nullable, /*@NonNull*/ R defaultValue) {
return nullable == null ? defaultValue : nullable;
}

private static final String DEFAULT_BLOCK_MSG = "Blocked by Sentinel (flow limiting)";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.param;

import com.alibaba.csp.sentinel.webflow.param.RequestItemParser;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;

/**
* Web item parser for {@code HttpServletRequest}.
*
* @since 1.8.8
*/
public class HttpServletRequestItemParser implements RequestItemParser<HttpServletRequest> {

@Override
public String getPath(HttpServletRequest request) {
return request.getPathInfo();
}

@Override
public String getRemoteAddress(HttpServletRequest request) {
return request.getRemoteAddr();
}

@Override
public String getHeader(HttpServletRequest request, String key) {
return request.getHeader(key);
}

@Override
public String getUrlParam(HttpServletRequest request, String paramName) {
return request.getParameter(paramName);
}

@Override
public String getCookieValue(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies == null || cookieName == null) {
return null;

Check warning on line 45 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L45

Added line #L45 was not covered by tests
}
for (Cookie cookie : cookies) {
if (cookie != null && cookieName.equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;

Check warning on line 52 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L52

Added line #L52 was not covered by tests
}

@Override
public String getBodyValue(HttpServletRequest request, String bodyName) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
String str;
StringBuilder wholeStr = new StringBuilder();
while ((str = br.readLine()) != null) {
wholeStr.append(str);
}
JSONObject jsonObject = JSONObject.parseObject(wholeStr.toString());
return jsonObject.get(bodyName).toString();
}catch (Throwable ignored){

Check warning on line 67 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L67

Added line #L67 was not covered by tests

}finally {
if(br != null){
try {
br.close();
} catch (IOException ignored) {

Check warning on line 73 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L73

Added line #L73 was not covered by tests

}
}
}

return null;

Check warning on line 79 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L79

Added line #L79 was not covered by tests
}

@Override
public String getPathValue(HttpServletRequest request, String pathName) {
try {
Map pathVariables = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return (String) pathVariables.get(pathName);
}catch (Throwable ignored){

Check warning on line 87 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L87

Added line #L87 was not covered by tests

}
return null;

Check warning on line 90 in sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java

View check run for this annotation

Codecov / codecov/patch

sentinel-adapter/sentinel-spring-webmvc-v6x-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc_v6x/param/HttpServletRequestItemParser.java#L90

Added line #L90 was not covered by tests
}

}
Loading
Loading