供应商已经通过HTTPS在名为XMLContent的表单变量中将XML数据发布到我的Coldfusion应用程序服务器。我最近转移到更新版本的应用程序服务器,这些请求导致500个服务器错误。它抛出了错误,因为第二个表单参数的内容没有正确地进行urlencoded,但我还是不需要那个参数。 (我联系了供应商来解决这个问题,但是他们强迫我付钱修理他们的错误,所以如果可能的话,我希望自己解决这个问题。)
我如何利用servlet过滤器删除名为XMLContent的表单参数以外的所有参数 我已尝试过各种尝试来显式删除有问题的参数“TContent”,但它永远不会被删除。
收到的数据片段:
XMLContent=%3C%3Fxml+version%3D%221.0%22+encoding%3D%22UTF-8%22%3F%3E%0A%3CCheck+xmlns%3D%22http .........&TContent=<!--?xml version="1.0" encoding="UTF-8"?--><check xmlns="http...........
我试过的代码:
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
public class MultipartFilter implements Filter {
// Init ----------------------------------------------------------------
public FilterConfig filterConfig;
// Actions -------------------------------------------------------------
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
/**
* Check the type request and if it is a HttpServletRequest, then parse the request.
* @throws ServletException If parsing of the given HttpServletRequest fails.
* @see javax.servlet.Filter#doFilter(
* javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException
{
// Check type request.
if (request instanceof HttpServletRequest) {
// Cast back to HttpServletRequest.
HttpServletRequest httpRequest = (HttpServletRequest) request;
// Parse HttpServletRequest.
HttpServletRequest parsedRequest = parseRequest(httpRequest);
// Continue with filter chain.
chain.doFilter(parsedRequest, response);
} else {
// Not a HttpServletRequest.
chain.doFilter(request, response);
}
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
this.filterConfig = null;
}
private HttpServletRequest parseRequest(HttpServletRequest request) throws ServletException {
// Prepare the request parameter map.
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
// Loop through form parameters.
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
// Add just the XMLContent form parameter
if (paramName.equalsIgnoreCase("xmlcontent")) {
parameterMap.put(paramName, new String[] { paramValues[0] });
}
}
// Wrap the request with the parameter map which we just created and return it.
return wrapRequest(request, parameterMap);
}
// Utility (may be refactored to public utility class) ---------------
/**
* Wrap the given HttpServletRequest with the given parameterMap.
* @param request The HttpServletRequest of which the given parameterMap have to be wrapped in.
* @param parameterMap The parameterMap to be wrapped in the given HttpServletRequest.
* @return The HttpServletRequest with the parameterMap wrapped in.
*/
private static HttpServletRequest wrapRequest(
HttpServletRequest request, final Map<String, String[]> parameterMap)
{
return new HttpServletRequestWrapper(request) {
public Map<String, String[]> getParameterMap() {
return parameterMap;
}
public String[] getParameterValues(String name) {
return parameterMap.get(name);
}
public String getParameter(String name) {
String[] params = getParameterValues(name);
return params != null && params.length > 0 ? params[0] : null;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameterMap.keySet());
}
};
}
}
答案 0 :(得分:6)
我们在处理区域设置时每天都会遇到这些情况。如果用户区域设置与浏览器区域设置不同,我们必须更新请求。但它不可变。
解决方案:创建一个请求包装类。将现有的请求参数(您想要的参数)复制到其中,并在filterchain.doFilter()中传递此包装类
样本包装类:
public class WrappedRequest extends HttpServletRequestWrapper
{
Map<String, String[]> parameterMap;
public WrappedRequest(final HttpServletRequest request)
{
//build your param Map here with required values
}
@Override
public Map<String, String[]> getParameterMap()
{
//return local param map
}
//override other methods if needed.
}
现在,在您的过滤器代码中,请执行以下操作。
wrapRequest = new WrappedRequest(hreq);
filterChain.doFilter(wrapRequest, servletResponse);
希望它能解决你的问题。
答案 1 :(得分:5)
<强>方法强>
代码遵循正确的方法:
在wrapRequest()
中,它实例化HttpServletRequestWrapper
并覆盖触发请求解析的4种方法:
public String getParameter(String name)
public Map<String, String[]> getParameterMap()
public Enumeration<String> getParameterNames()
public String[] getParameterValues(String name)
doFilter()
方法使用包装请求调用过滤器链,这意味着后续过滤器和目标servlet(URL映射)将提供包装请求。
<强>问题强>
Request.parseRequestParameters or parsePameters
)。这4种方法是触发此类解析的唯一方法。在请求被包装之前,在parseRequest()
中,您的代码会在基础请求中调用此类方法:
request.getParameterNames();
request.getParameterValues(paramName);
<强>解决方案强>
您需要控制解析逻辑。从输入流中读取原始字节并进行自己的URL解码过于复杂 - 这意味着要替换大量紧密耦合的服务器代码。相反,最简单的方法是只替换执行实际URL解码的方法。这意味着您可以保留上一节中提到的request.getParameterXXX
来电。
不确定您正在托管ColdFusion的服务器,但以下描述基于Glassfish / Tomcat,但可以进行调整。这篇文章的底部是Glassfish的内部请求解析方法(Tomcat的修改版本)。 JD-decompiler对于将.class文件转换为.java进行修补非常有用。
com.sun.grizzly.util.http.Parameters
来自grizzly-utils.jar
,如下所示,对于Tomcat,这是来自org.apache.tomcat.util.http.Parameters
的{{1}} tomcat-coyote.jar
somepackage.StrippedParameters
)更改此代码,使其仅在参数名称与所需参数匹配时进行解码:
value = urlDecode(this.tmpValue)
现在是棘手的部分:在发生URL解码之前,用类if (decodeName)
name = urlDecode(this.tmpName);
else
name = this.tmpName.toString();
//
// !! THIS IF STATEMENT ADDED TO ONLY DECODE DESIRED PARAMETERS,
// !! OTHERS ARE STRIPPED:
//
if ("XMLContent".equals(name)) {
String value;
String value;
if (decodeValue)
value = urlDecode(this.tmpValue);
else {
value = this.tmpValue.toString();
}
try
{
addParameter(name, value);
}
catch (IllegalStateException ise)
{
logger.warning(ise.getMessage());
break;
}
}
替换默认类Parameters
。获取参数后,将它们复制回容器类。对于Glassfish,将方法parseRequestParameters复制到HttpServletRequestWrapper的实现中(对于Tomcat,StrippedParmeters
中的类parseParameters
中的相应方法为org.apache.catalina.connector.Request
替换此行:
catalina.jar
使用:
Parameters parameters = this.coyoteRequest.getParameters();
在方法的底部,添加:
Parameters parameters = new somepackage.StrippedParameters();
Glassfish容器代码 - Tomcat的修改版本,Grizzly取代Coyote (Catalina Servlet Engine仍然指的是Coyote对象,但它们是像Coyote一样被嘲笑的Grizzly实例)
Parameters coyoteParameters = this.coyoteRequest.getParameters();
for (String paramName : parameters.getParameterNames()) {
String paramValue = parameters.getParameterValue(paramName);
coyoteParameters.addParameter(paramName, paramValue);
}
package org.apache.catalina.connector;
....
public class Request implements HttpRequest, HttpServletRequest {
....
protected com.sun.grizzly.tcp.Request coyoteRequest;
....
// This is called from the 4 methods named 'getParameterXXX'
protected void parseRequestParameters() {
Parameters parameters = this.coyoteRequest.getParameters();
parameters.setLimit(getConnector().getMaxParameterCount());
String enc = getCharacterEncoding();
this.requestParametersParsed = true;
if (enc != null) {
parameters.setEncoding(enc);
parameters.setQueryStringEncoding(enc);
} else {
parameters.setEncoding("ISO-8859-1");
parameters.setQueryStringEncoding("ISO-8859-1");
}
parameters.handleQueryParameters();
if ((this.usingInputStream) || (this.usingReader)) {
return;
}
if (!getMethod().equalsIgnoreCase("POST")) {
return;
}
String contentType = getContentType();
if (contentType == null) {
contentType = "";
}
int semicolon = contentType.indexOf(';');
if (semicolon >= 0)
contentType = contentType.substring(0, semicolon).trim();
else {
contentType = contentType.trim();
}
if ((isMultipartConfigured()) && ("multipart/form-data".equals(contentType))) {
getMultipart().init();
}
if (!"application/x-www-form-urlencoded".equals(contentType)) {
return;
}
int len = getContentLength();
if (len > 0) {
int maxPostSize = ((Connector)this.connector).getMaxPostSize();
if ((maxPostSize > 0) && (len > maxPostSize)) {
log(sm.getString("coyoteRequest.postTooLarge"));
throw new IllegalStateException("Post too large");
}
try {
byte[] formData = getPostBody();
if (formData != null)
parameters.processParameters(formData, 0, len);
} catch (Throwable t) {
}
}
}
}
package com.sun.grizzly.tcp;
import com.sun.grizzly.util.http.Parameters;
public class Request {
....
private Parameters parameters = new Parameters();
....
public Parameters getParameters() {
return this.parameters;
}
}
}