org.springframework.web.filter.EncodingFilter Maven / Gradle / Ivy
package org.springframework.web.filter;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
public class EncodingFilter extends OncePerRequestFilter implements Ordered {
private static final Set CHARSETS = Collections.newSetFromMap(new LinkedCaseInsensitiveMap(5, Locale.ENGLISH));
private static final Map ESCAPES = new LinkedHashMap();
private int order = Ordered.HIGHEST_PRECEDENCE + 50;
private Charset charset;
static {
CHARSETS.add(StandardCharsets.ISO_8859_1.name());
CHARSETS.add(StandardCharsets.UTF_16.name());
CHARSETS.add(StandardCharsets.UTF_16BE.name());
CHARSETS.add(StandardCharsets.UTF_16LE.name());
CHARSETS.add(StandardCharsets.US_ASCII.name());
ESCAPES.put("|", "%7C");
ESCAPES.put(" ", "%20");
ESCAPES.put("^", "%5E");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = request.getCharacterEncoding();
if (encoding == null) {
Charset charset = getCharset();
if (charset == null) {
charset = Charset.defaultCharset();
}
encoding = charset.name();
}
Assert.notNull(encoding, "'encoding' must not be null");
filterChain.doFilter(new CharsetEscapeRequestWrapper(request, encoding), response);
}
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public Charset getCharset() {
return charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
private static class CharsetEscapeRequestWrapper extends HttpServletRequestWrapper {
private final StringBuffer requestURL;
private final String requestURI;
private final String queryString;
public CharsetEscapeRequestWrapper(HttpServletRequest request, String encoding) {
super(request);
String requestURL, requestURI, queryString;
if (request.getRequestURL() != null && StringUtils.hasText(requestURL = new String(request.getRequestURL()))) {
requestURL = replace(requestURL);
try {
URI.create(requestURL).toASCIIString();
}
catch (IllegalArgumentException e) {
requestURL = convert(requestURL, encoding);
}
this.requestURL = new StringBuffer(requestURL);
}
else {
this.requestURL = request.getRequestURL();
}
if (StringUtils.hasText(requestURI = request.getRequestURI())) {
requestURI = replace(requestURI);
try {
URI.create(requestURI).toASCIIString();
}
catch (IllegalArgumentException e) {
requestURI = convert(requestURI, encoding);
}
this.requestURI = requestURI;
}
else {
this.requestURI = requestURI;
}
if (StringUtils.hasText(queryString = request.getQueryString())) {
queryString = replace(queryString);
try {
URI.create(queryString).toASCIIString();
}
catch (IllegalArgumentException e) {
queryString = convert(queryString, encoding);
}
this.queryString = queryString;
}
else {
this.queryString = queryString;
}
}
private String replace(String string) {
for (Entry entry : ESCAPES.entrySet()) {
string = string.replace(entry.getKey(), entry.getValue());
}
return string;
}
private String convert(String string, String characterEncoding) {
for (String charset : CHARSETS) {
try {
return convert(string, charset, characterEncoding);
}
catch (Exception e) {
continue;
}
}
return string;
}
private String convert(String string, String charsetName, String characterEncoding) throws Exception {
try {
return URI.create(new String(string.getBytes(charsetName), characterEncoding)).toASCIIString();
}
catch (IOException | IllegalArgumentException e) {
throw e;
}
}
@Override
public String getRequestURI() {
return this.requestURI;
}
@Override
public StringBuffer getRequestURL() {
return this.requestURL;
}
@Override
public String getQueryString() {
return this.queryString;
}
}
}