Return-Path: X-Original-To: apmail-tomcat-dev-archive@www.apache.org Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 70D10E514 for ; Sat, 2 Mar 2013 22:05:55 +0000 (UTC) Received: (qmail 23412 invoked by uid 500); 2 Mar 2013 22:05:54 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 23331 invoked by uid 500); 2 Mar 2013 22:05:54 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 23319 invoked by uid 99); 2 Mar 2013 22:05:54 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 02 Mar 2013 22:05:54 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 02 Mar 2013 22:05:51 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 849CD23888EA for ; Sat, 2 Mar 2013 22:04:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1451947 - in /tomcat/trunk: java/org/apache/catalina/connector/CoyoteAdapter.java java/org/apache/tomcat/util/buf/B2CConverter.java test/org/apache/catalina/connector/TestCoyoteAdapter.java Date: Sat, 02 Mar 2013 22:04:47 -0000 To: dev@tomcat.apache.org From: markt@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130302220447.849CD23888EA@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org