Author: markt Date: Sat Mar 2 22:04:46 2013 New Revision: 1451947 URL: http://svn.apache.org/r1451947 Log: Remove fall back to 'ASCII' (really ISO-8859-1) Replace partial / invalid byte sequences rather than trigger an error (allows application to handle the resulting 404)
Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java tomcat/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteAdapter.java Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1451947&r1=1451946&r2=1451947&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java (original) +++ tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Sat Mar 2 22:04:46 2013 @@ -23,6 +23,7 @@ import java.util.EnumSet; import javax.servlet.RequestDispatcher; import javax.servlet.SessionTrackingMode; +import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Host; @@ -1034,30 +1035,30 @@ public class CoyoteAdapter implements Ad B2CConverter conv = request.getURIConverter(); try { if (conv == null) { - conv = new B2CConverter(enc); + conv = new B2CConverter(enc, true); request.setURIConverter(conv); } else { conv.recycle(); } } catch (IOException e) { - // Ignore log.error("Invalid URI encoding; using HTTP default"); connector.setURIEncoding(null); } if (conv != null) { try { conv.convert(bc, cc, true); - uri.setChars(cc.getBuffer(), cc.getStart(), - cc.getLength()); + uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength()); return; - } catch (IOException e) { - log.error("Invalid URI character encoding; trying ascii"); - cc.recycle(); + } catch (IOException ioe) { + // Should never happen as B2CConverter should replace + // problematic characters + request.getResponse().sendError( + HttpServletResponse.SC_BAD_REQUEST); } } } - // Default encoding: fast conversion + // Default encoding: fast conversion for ISO-8859-1 byte[] bbuf = bc.getBuffer(); char[] cbuf = cc.getBuffer(); int start = bc.getStart(); @@ -1065,7 +1066,6 @@ public class CoyoteAdapter implements Ad cbuf[i] = (char) (bbuf[i + start] & 0xff); } uri.setChars(cbuf, 0, length); - } Modified: tomcat/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java?rev=1451947&r1=1451946&r2=1451947&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/buf/B2CConverter.java Sat Mar 2 22:04:46 2013 @@ -23,6 +23,7 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -103,9 +104,22 @@ public class B2CConverter { private final ByteBuffer leftovers; public B2CConverter(String encoding) throws IOException { + this(encoding, false); + } + + public B2CConverter(String encoding, boolean replaceOnError) + throws IOException { byte[] left = new byte[LEFTOVER_SIZE]; leftovers = ByteBuffer.wrap(left); + CodingErrorAction action; + if (replaceOnError) { + action = CodingErrorAction.REPLACE; + } else { + action = CodingErrorAction.REPORT; + } decoder = getCharset(encoding).newDecoder(); + decoder.onMalformedInput(action); + decoder.onUnmappableCharacter(action); } /** Modified: tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteAdapter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteAdapter.java?rev=1451947&r1=1451946&r2=1451947&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteAdapter.java (original) +++ tomcat/trunk/test/org/apache/catalina/connector/TestCoyoteAdapter.java Sat Mar 2 22:04:46 2013 @@ -25,9 +25,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - +import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; @@ -89,7 +87,7 @@ public class TestCoyoteAdapter extends T File foo = new File(docBase, "foo"); addDeleteOnTearDown(foo); if (!foo.mkdirs() && !foo.isDirectory()) { - fail("Unable to create foo directory in docBase"); + Assert.fail("Unable to create foo directory in docBase"); } Context ctx = tomcat.addContext("", docBase.getAbsolutePath()); @@ -122,12 +120,12 @@ public class TestCoyoteAdapter extends T tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + path); - assertEquals(expected, res.toString()); + Assert.assertEquals(expected, res.toString()); } private void testPath(String path, String expected) throws Exception { ByteChunk res = getUrl("http://localhost:" + getPort() + path); - assertEquals(expected, res.toString()); + Assert.assertEquals(expected, res.toString()); } private static class PathParamServlet extends HttpServlet { @@ -176,6 +174,68 @@ public class TestCoyoteAdapter extends T tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + path); - assertEquals(expected, res.toString()); + Assert.assertEquals(expected, res.toString()); + } + + @Test + public void testBug54602a() throws Exception { + // No UTF-8 + doTestUriDecoding("/foo", "UTF-8", "/foo"); + } + + @Test + public void testBug54602b() throws Exception { + // Valid UTF-8 + doTestUriDecoding("/foo%c4%87", "UTF-8", "/foo\u0107"); + } + + @Test + public void testBug54602c() throws Exception { + // Partial UTF-8 + doTestUriDecoding("/foo%c4", "UTF-8", "/foo\uFFFD"); + } + + private void doTestUriDecoding(String path, String encoding, + String expectedPathInfo) throws Exception{ + + // Setup Tomcat instance + Tomcat tomcat = getTomcatInstance(); + + tomcat.getConnector().setURIEncoding(encoding); + + // Must have a real docBase - just use temp + Context ctx = + tomcat.addContext("/", System.getProperty("java.io.tmpdir")); + + PathInfoServlet servlet = new PathInfoServlet(); + Tomcat.addServlet(ctx, "servlet", servlet); + ctx.addServletMapping("/*", "servlet"); + + tomcat.start(); + + int rc = getUrl("http://localhost:" + getPort() + path, + new ByteChunk(), null); + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + + Assert.assertEquals(expectedPathInfo, servlet.getPathInfo()); + } + + private static class PathInfoServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private String pathInfo = null; + + public String getPathInfo() { + return pathInfo; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + // Not thread safe + pathInfo = req.getPathInfo(); + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org