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: [email protected]
For additional commands, e-mail: [email protected]