From 90d5611b23f3f70c8b09b357e61e2be91aa4920f Mon Sep 17 00:00:00 2001 From: Eric Zhao Date: Thu, 20 Sep 2018 23:19:17 +0800 Subject: [PATCH] Update Sentinel Web Servlet integration - Add RequestOriginParser interface to extract request origin from the HTTP request - Some code refinement Signed-off-by: Eric Zhao --- .../sentinel-web-servlet/README.md | 19 ++++++++-- .../adapter/servlet/CommonFilter.java | 32 +++++++++++++++-- .../servlet/callback/RequestOriginParser.java | 35 +++++++++++++++++++ .../servlet/callback/WebCallbackManager.java | 18 ++++++++-- 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/callback/RequestOriginParser.java 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; + } }