- Add RequestOriginParser interface to extract request origin from the HTTP request - Some code refinement Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -1,7 +1,16 @@ | |||||
# Sentinel Web Servlet Filter | # 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 | |||||
<dependency> | |||||
<groupId>com.alibaba.csp</groupId> | |||||
<artifactId>sentinel-web-servlet</artifactId> | |||||
<version>x.y.z</version> | |||||
</dependency> | |||||
``` | |||||
To use the filter, you can simply configure your `web.xml` with: | |||||
```xml | ```xml | ||||
<filter> | <filter> | ||||
@@ -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 | the filter will redirect the request to provided URL. You can also implement your own | ||||
block handler (the `UrlBlockHandler` interface) and register to `WebCallbackManager`. | 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`. |
@@ -30,15 +30,19 @@ import com.alibaba.csp.sentinel.Entry; | |||||
import com.alibaba.csp.sentinel.EntryType; | import com.alibaba.csp.sentinel.EntryType; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | 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.callback.WebCallbackManager; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | ||||
import com.alibaba.csp.sentinel.context.ContextUtil; | import com.alibaba.csp.sentinel.context.ContextUtil; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/*** | /*** | ||||
* Servlet filter that integrates with Sentinel. | * Servlet filter that integrates with Sentinel. | ||||
* | * | ||||
* @author youji.zj | * @author youji.zj | ||||
* @author Eric Zhao | |||||
*/ | */ | ||||
public class CommonFilter implements Filter { | public class CommonFilter implements Filter { | ||||
@@ -55,14 +59,24 @@ public class CommonFilter implements Filter { | |||||
try { | try { | ||||
String target = FilterUtil.filterTarget(sRequest); | 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); | entry = SphU.entry(target, EntryType.IN); | ||||
chain.doFilter(request, response); | chain.doFilter(request, response); | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
HttpServletResponse sResponse = (HttpServletResponse)response; | HttpServletResponse sResponse = (HttpServletResponse)response; | ||||
// Return the block page, or redirect to another URL. | |||||
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse); | WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse); | ||||
} catch (IOException e2) { | } catch (IOException e2) { | ||||
Tracer.trace(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 | @Override | ||||
public void destroy() { | public void destroy() { | ||||
} | } | ||||
private static final String EMPTY_ORIGIN = ""; | |||||
} | } |
@@ -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); | |||||
} |
@@ -15,6 +15,8 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.servlet.callback; | package com.alibaba.csp.sentinel.adapter.servlet.callback; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | |||||
/** | /** | ||||
* Registry for URL cleaner and URL block handler. | * Registry for URL cleaner and URL block handler. | ||||
* | * | ||||
@@ -23,15 +25,17 @@ package com.alibaba.csp.sentinel.adapter.servlet.callback; | |||||
public class WebCallbackManager { | public class WebCallbackManager { | ||||
/** | /** | ||||
* URL cleaner | |||||
* URL cleaner. | |||||
*/ | */ | ||||
private static volatile UrlCleaner urlCleaner = new DefaultUrlCleaner(); | private static volatile UrlCleaner urlCleaner = new DefaultUrlCleaner(); | ||||
/** | /** | ||||
* URL block handler | |||||
* URL block handler. | |||||
*/ | */ | ||||
private static volatile UrlBlockHandler urlBlockHandler = new DefaultUrlBlockHandler(); | private static volatile UrlBlockHandler urlBlockHandler = new DefaultUrlBlockHandler(); | ||||
private static volatile RequestOriginParser requestOriginParser = null; | |||||
public static UrlCleaner getUrlCleaner() { | public static UrlCleaner getUrlCleaner() { | ||||
return urlCleaner; | return urlCleaner; | ||||
} | } | ||||
@@ -45,6 +49,16 @@ public class WebCallbackManager { | |||||
} | } | ||||
public static void setUrlBlockHandler(UrlBlockHandler urlBlockHandler) { | public static void setUrlBlockHandler(UrlBlockHandler urlBlockHandler) { | ||||
AssertUtil.isTrue(urlBlockHandler != null, "URL block handler should not be null"); | |||||
WebCallbackManager.urlBlockHandler = urlBlockHandler; | WebCallbackManager.urlBlockHandler = urlBlockHandler; | ||||
} | } | ||||
public static RequestOriginParser getRequestOriginParser() { | |||||
return requestOriginParser; | |||||
} | |||||
public static void setRequestOriginParser( | |||||
RequestOriginParser requestOriginParser) { | |||||
WebCallbackManager.requestOriginParser = requestOriginParser; | |||||
} | |||||
} | } |