Author: markt Date: Sat Jul 10 21:13:23 2010 New Revision: 962917 URL: http://svn.apache.org/viewvc?rev=962917&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49478 Add support for user specified character sets to the AddDefaultCharsetFilter. Based on a patch by Felix Schumacher.
Added: tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java (with props) Modified: tomcat/trunk/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java tomcat/trunk/java/org/apache/catalina/filters/LocalStrings.properties tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/filter.xml Modified: tomcat/trunk/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java?rev=962917&r1=962916&r2=962917&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java (original) +++ tomcat/trunk/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java Sat Jul 10 21:13:23 2010 @@ -17,10 +17,9 @@ package org.apache.catalina.filters; - import java.io.IOException; +import java.nio.charset.Charset; -import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; @@ -29,24 +28,54 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + /** * Filter that explicitly sets the default character set for media subtypes of - * the "text" type to ISO-8859-1. RFC2616 explicitly states that browsers must - * use ISO-8859-1 in these circumstances. However, browsers may attempt to + * the "text" type to ISO-8859-1, or another user defined character set. RFC2616 + * explicitly states that browsers must use ISO-8859-1 if no character set is + * defined for media with subtype "text". However, browsers may attempt to * auto-detect the character set. This may be exploited by an attacker to * perform an XSS attack. Internet Explorer has this behaviour by default. Other - * browsers have an option to enable it. + * browsers have an option to enable it.<br/> * * This filter prevents the attack by explicitly setting a character set. Unless * the provided character set is explicitly overridden by the user - in which * case they deserve everything they get - the browser will adhere to an * explicitly set character set, thus preventing the XSS attack. */ -public class AddDefaultCharsetFilter implements Filter { +public class AddDefaultCharsetFilter extends FilterBase { + + private static final Log log = + LogFactory.getLog(AddDefaultCharsetFilter.class); + + private static final String DEFAULT_ENCODING = "ISO-8859-1"; + + private String encoding; + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + protected Log getLogger() { + return log; + } - public void destroy() { - // NOOP + @Override + public void init(FilterConfig filterConfig) throws ServletException { + super.init(filterConfig); + if (encoding == null || encoding.length() == 0 || + encoding.equalsIgnoreCase("default")) { + encoding = DEFAULT_ENCODING; + } else if (encoding.equalsIgnoreCase("system")) { + encoding = Charset.defaultCharset().name(); + } else if (!Charset.isSupported(encoding)) { + throw new IllegalArgumentException(sm.getString( + "addDefaultCharset.unsupportedCharset", encoding)); + } } public void doFilter(ServletRequest request, ServletResponse response, @@ -55,40 +84,46 @@ public class AddDefaultCharsetFilter imp // Wrap the response if (response instanceof HttpServletResponse) { ResponseWrapper wrapped = - new ResponseWrapper((HttpServletResponse)response); + new ResponseWrapper((HttpServletResponse)response, encoding); chain.doFilter(request, wrapped); } else { chain.doFilter(request, response); } } - public void init(FilterConfig filterConfig) throws ServletException { - // NOOP - } - /** - * Wrapper that adds the default character set for text media types if no - * character set is specified. + * Wrapper that adds a character set for text media types if no character + * set is specified. */ - public class ResponseWrapper extends HttpServletResponseWrapper { + public static class ResponseWrapper extends HttpServletResponseWrapper { + + private String encoding; + + public ResponseWrapper(HttpServletResponse response, String encoding) { + super(response); + this.encoding = encoding; + } @Override public void setContentType(String ct) { - if (ct != null && ct.startsWith("text/") && - ct.indexOf("charset=") < 0) { - // Use getCharacterEncoding() in case the charset has already - // been set by a separate call. - super.setContentType(ct + ";charset=" + getCharacterEncoding()); + if (ct != null && ct.startsWith("text/")) { + if (ct.indexOf("charset=") < 0) { + super.setContentType(ct + ";charset=" + encoding); + } else { + super.setContentType(ct); + encoding = getCharacterEncoding(); + } } else { super.setContentType(ct); } } - public ResponseWrapper(HttpServletResponse response) { - super(response); + @Override + public void setCharacterEncoding(String charset) { + super.setCharacterEncoding(charset); + encoding = charset; } - } } Modified: tomcat/trunk/java/org/apache/catalina/filters/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/filters/LocalStrings.properties?rev=962917&r1=962916&r2=962917&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/filters/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/filters/LocalStrings.properties Sat Jul 10 21:13:23 2010 @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +addDefaultCharset.unsupportedCharset=Specified character set [{0}] is not supported csrfPrevention.invalidRandomClass=Unable to create Random source using class [{0}] filterbase.noSuchProperty=The property "{0}" is not defined for filters of type "{1}" Added: tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java?rev=962917&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java (added) +++ tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java Sat Jul 10 21:13:23 2010 @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.filters; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +public class TestAddCharSetFilter extends TomcatBaseTest { + + public void testNoneSpecifiedMode1() throws Exception { + doTest(null, "ISO-8859-1"); + } + + public void testNoneSpecifiedMode2() throws Exception { + doTest(null, "ISO-8859-2", 2); + } + + public void testNoneSpecifiedMode3() throws Exception { + doTest(null, "ISO-8859-3", 3); + } + + public void testDefault() throws Exception { + doTest("default", "ISO-8859-1"); + } + + public void testDefaultMixedCase() throws Exception { + doTest("dEfAuLt", "ISO-8859-1"); + } + + public void testSystem() throws Exception { + doTest("system", Charset.defaultCharset().name()); + } + + public void testSystemMixedCase() throws Exception { + doTest("SyStEm", Charset.defaultCharset().name()); + } + + public void testUTF8() throws Exception { + doTest("utf-8", "utf-8"); + } + + + private void doTest(String encoding, String expected) throws Exception { + doTest(encoding, expected, 1); + } + + private void doTest(String encoding, String expected, int mode) + throws Exception { + // Setup Tomcat instance + Tomcat tomcat = getTomcatInstance(); + + // Must have a real docBase - just use temp + Context ctx = + tomcat.addContext("/", System.getProperty("java.io.tmpdir")); + + // Add the Servlet + CharsetServlet servlet = new CharsetServlet(mode); + Tomcat.addServlet(ctx, "servlet", servlet); + ctx.addServletMapping("/", "servlet"); + + // Add the Filter + FilterDef filterDef = new FilterDef(); + filterDef.setFilterClass(AddDefaultCharsetFilter.class.getName()); + filterDef.setFilterName("filter"); + if (encoding != null) { + filterDef.addInitParameter("encoding", encoding); + } + ctx.addFilterDef(filterDef); + FilterMap filterMap = new FilterMap(); + filterMap.setFilterName("filter"); + filterMap.addServletName("servlet"); + ctx.addFilterMap(filterMap); + + tomcat.start(); + + Map<String, List<String>> headers = new HashMap<String, List<String>>(); + getUrl("http://localhost:" + getPort() + "/", new ByteChunk(), headers); + + List<String> ctHeaders = headers.get("Content-Type"); + assertEquals(1, ctHeaders.size()); + String ct = ctHeaders.get(0); + assertEquals("text/plain;charset=" + expected, ct); + } + + private static class CharsetServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final String OUTPUT = "OK"; + + private final int mode; + + public CharsetServlet(int mode) { + this.mode = mode; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + switch (mode) { + case 1: + resp.setContentType("text/plain"); + break; + case 2: + resp.setContentType("text/plain;charset=ISO-8859-2"); + break; + case 3: + resp.setContentType("text/plain"); + resp.setCharacterEncoding("ISO-8859-3"); + break; + default: + resp.setContentType("text/plain;charset=ISO-8859-4"); + break; + } + resp.getWriter().print(OUTPUT); + } + } +} Propchange: tomcat/trunk/test/org/apache/catalina/filters/TestAddCharSetFilter.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=962917&r1=962916&r2=962917&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Sat Jul 10 21:13:23 2010 @@ -83,6 +83,11 @@ Use a LockOutRealm in the default configuration to prevent attempts to guess user passwords by brute-force. (markt) </add> + <add> + <bug>49478</bug>: Add support for user specified character sets to the + <code>AddDefaultCharsetFilter</code>. Based on a patch by Felix + Schumacher. (markt) + </add> <fix> <bug>49503</bug>: Make sure connectors bind to their associated ports sufficiently early to allow jsvc and the Modified: tomcat/trunk/webapps/docs/config/filter.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/filter.xml?rev=962917&r1=962916&r2=962917&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/filter.xml (original) +++ tomcat/trunk/webapps/docs/config/filter.xml Sat Jul 10 21:13:23 2010 @@ -79,8 +79,20 @@ <subsection name="Initialisation parameters"> - <p>The Add Default Character Set Filter does not support any initialization - parameters.</p> + <p>The Add Default Character Set Filter supports the following initialization + parameters:</p> + + <attributes> + + <attribute name="encoding" required="false"> + <p>Name of the character set which should be set, if no other character set + was set explicitly by a Servlet. This parameter has two special values + <code>default</code> and <code>system</code>. A value of <code>system</code> + uses the JVM wide default character set, which is usually set by locale. + A value of <code>default</code> will use <strong>ISO-8859-1</strong>.</p> + </attribute> + + </attributes> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org