diff --git a/sentinel-adapter/sentinel-web-servlet/README.md b/sentinel-adapter/sentinel-web-servlet/README.md
index 39bfefc2..21a25b3a 100755
--- a/sentinel-adapter/sentinel-web-servlet/README.md
+++ b/sentinel-adapter/sentinel-web-servlet/README.md
@@ -1,7 +1,16 @@
# Sentinel Web Servlet Filter
-Sentinel provides Servlet filter integration. To use the filter,
-you can simply configure your `web.xml` with:
+Sentinel provides Servlet filter integration to enable flow control for web requests. Add the following dependency in `pom.xml` (if you are using Maven):
+
+```xml
+
+ com.alibaba.csp
+ sentinel-web-servlet
+ x.y.z
+
+```
+
+To use the filter, you can simply configure your `web.xml` with:
```xml
@@ -20,3 +29,9 @@ If customized block page is set (via `WebServletConfig.setBlockPage(blockPage)`
the filter will redirect the request to provided URL. You can also implement your own
block handler (the `UrlBlockHandler` interface) and register to `WebCallbackManager`.
+The `UrlCleaner` interface is designed for clean and unify the URL resource.
+For REST APIs, you have to clean the URL resource (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or
+the amount of context and resources will exceed the threshold.
+
+`RequestOriginParser` interface is useful for extracting request origin (e.g. IP or appName from HTTP Header)
+from HTTP request. You can implement your own `RequestOriginParser` and register to `WebCallbackManager`.
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java
index 7ca3fe27..a3c8d008 100755
--- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java
+++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java
@@ -30,15 +30,19 @@ import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.StringUtil;
/***
* Servlet filter that integrates with Sentinel.
*
* @author youji.zj
+ * @author Eric Zhao
*/
public class CommonFilter implements Filter {
@@ -55,14 +59,24 @@ public class CommonFilter implements Filter {
try {
String target = FilterUtil.filterTarget(sRequest);
- target = WebCallbackManager.getUrlCleaner().clean(target);
+ // Clean and unify the URL.
+ // For REST APIs, you have to clean the URL (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or
+ // the amount of context and resources will exceed the threshold.
+ UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner();
+ if (urlCleaner != null) {
+ target = urlCleaner.clean(target);
+ }
+
+ // Parse the request origin using registered origin parser.
+ String origin = parseOrigin(sRequest);
- ContextUtil.enter(target);
+ ContextUtil.enter(target, origin);
entry = SphU.entry(target, EntryType.IN);
chain.doFilter(request, response);
} catch (BlockException e) {
HttpServletResponse sResponse = (HttpServletResponse)response;
+ // Return the block page, or redirect to another URL.
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse);
} catch (IOException e2) {
Tracer.trace(e2);
@@ -81,8 +95,22 @@ public class CommonFilter implements Filter {
}
}
+ private String parseOrigin(HttpServletRequest request) {
+ RequestOriginParser originParser = WebCallbackManager.getRequestOriginParser();
+ String origin = EMPTY_ORIGIN;
+ if (originParser != null) {
+ origin = originParser.parseOrigin(request);
+ if (StringUtil.isEmpty(origin)) {
+ return EMPTY_ORIGIN;
+ }
+ }
+ return origin;
+ }
+
@Override
public void destroy() {
}
+
+ private static final String EMPTY_ORIGIN = "";
}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/RequestOriginParser.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/RequestOriginParser.java
new file mode 100644
index 00000000..185ff291
--- /dev/null
+++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/RequestOriginParser.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.servlet.callback;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * The origin parser parses request origin (e.g. IP, user, appName) from HTTP request.
+ *
+ * @author Eric Zhao
+ * @since 0.2.0
+ */
+public interface RequestOriginParser {
+
+ /**
+ * Parse the origin from given HTTP request.
+ *
+ * @param request HTTP request
+ * @return parsed origin
+ */
+ String parseOrigin(HttpServletRequest request);
+}
diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
index 435dd9db..af392e51 100755
--- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
+++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/WebCallbackManager.java
@@ -15,6 +15,8 @@
*/
package com.alibaba.csp.sentinel.adapter.servlet.callback;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
/**
* Registry for URL cleaner and URL block handler.
*
@@ -23,15 +25,17 @@ package com.alibaba.csp.sentinel.adapter.servlet.callback;
public class WebCallbackManager {
/**
- * URL cleaner
+ * URL cleaner.
*/
private static volatile UrlCleaner urlCleaner = new DefaultUrlCleaner();
/**
- * URL block handler
+ * URL block handler.
*/
private static volatile UrlBlockHandler urlBlockHandler = new DefaultUrlBlockHandler();
+ private static volatile RequestOriginParser requestOriginParser = null;
+
public static UrlCleaner getUrlCleaner() {
return urlCleaner;
}
@@ -45,6 +49,16 @@ public class WebCallbackManager {
}
public static void setUrlBlockHandler(UrlBlockHandler urlBlockHandler) {
+ AssertUtil.isTrue(urlBlockHandler != null, "URL block handler should not be null");
WebCallbackManager.urlBlockHandler = urlBlockHandler;
}
+
+ public static RequestOriginParser getRequestOriginParser() {
+ return requestOriginParser;
+ }
+
+ public static void setRequestOriginParser(
+ RequestOriginParser requestOriginParser) {
+ WebCallbackManager.requestOriginParser = requestOriginParser;
+ }
}