Author: markt
Date: Fri Jun 30 20:29:51 2017
New Revision: 1800454
URL: http://svn.apache.org/viewvc?rev=1800454&view=rev
Log:
Improve the Default Servlet's handling of static files when the file encoding
is not compatible with the required response encoding.
Added:
tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt (with props)
Modified:
tomcat/trunk/build.xml
tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java
tomcat/trunk/test/org/apache/catalina/servlets/TestDefaultServlet.java
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/build.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/build.xml?rev=1800454&r1=1800453&r2=1800454&view=diff
==============================================================================
--- tomcat/trunk/build.xml (original)
+++ tomcat/trunk/build.xml Fri Jun 30 20:29:51 2017
@@ -560,6 +560,7 @@
<exclude name="java/org/apache/**/parser/Token*.java" />
<!-- Exclude simple test files -->
<exclude name="test/webapp/bug53257/**/*.txt"/>
+ <exclude name="test/webapp/bug49nnn/bug49464-ibm850.txt"/>
<exclude name="test/webapp-fragments/WEB-INF/classes/*.txt"/>
<exclude name="test/webresources/**"/>
<!-- Exclude test files with unusual encodings -->
Modified: tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java?rev=1800454&r1=1800453&r2=1800454&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java Fri Jun
30 20:29:51 2017
@@ -32,6 +32,8 @@ import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.util.ArrayList;
@@ -73,6 +75,7 @@ import org.apache.catalina.connector.Res
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.util.URLEncoder;
+import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.res.StringManager;
import org.apache.tomcat.util.security.PrivilegedGetTccl;
import org.apache.tomcat.util.security.PrivilegedSetTccl;
@@ -230,6 +233,7 @@ public class DefaultServlet extends Http
* the platform default is used.
*/
protected String fileEncoding = null;
+ private Charset fileEncodingCharset = null;
/**
* Minimum size for sendfile usage in bytes.
@@ -287,6 +291,16 @@ public class DefaultServlet extends Http
Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024;
fileEncoding = getServletConfig().getInitParameter("fileEncoding");
+ if (fileEncoding == null) {
+ fileEncodingCharset = Charset.defaultCharset();
+ fileEncoding = fileEncodingCharset.name();
+ } else {
+ try {
+ fileEncodingCharset = B2CConverter.getCharset(fileEncoding);
+ } catch (UnsupportedEncodingException e) {
+ throw new ServletException(e);
+ }
+ }
globalXsltFile = getServletConfig().getInitParameter("globalXsltFile");
contextXsltFile =
getServletConfig().getInitParameter("contextXsltFile");
@@ -938,7 +952,7 @@ public class DefaultServlet extends Http
}
}
- // Check to see if a Filter, Valve of wrapper has written some content.
+ // Check to see if a Filter, Valve or wrapper has written some content.
// If it has, disable range requests and setting of a content length
// since neither can be done reliably.
ServletResponse r = response;
@@ -1000,19 +1014,38 @@ public class DefaultServlet extends Http
renderResult = render(getPathPrefix(request),
resource, encoding);
} else {
// Output is content of resource
- if (!checkSendfile(request, response, resource,
- contentLength, null)) {
- // sendfile not possible so check if resource
- // content is available directly
+ // Check to see if conversion is required
+ String outputEncoding =
response.getCharacterEncoding();
+ Charset charset =
B2CConverter.getCharset(outputEncoding);
+ if (charset.equals(fileEncodingCharset)) {
+ if (!checkSendfile(request, response, resource,
+ contentLength, null)) {
+ // sendfile not possible so check if resource
+ // content is available directly
+ byte[] resourceBody = resource.getContent();
+ if (resourceBody == null) {
+ // Resource content not available, use
+ // inputstream
+ renderResult = resource.getInputStream();
+ } else {
+ // Use the resource content directly
+ ostream.write(resourceBody);
+ }
+ }
+ } else {
+ // A conversion is required from fileEncoding to
+ // response encoding
byte[] resourceBody = resource.getContent();
+ InputStream source;
if (resourceBody == null) {
- // Resource content not available, use
- // inputstream
- renderResult = resource.getInputStream();
+ source = resource.getInputStream();
} else {
- // Use the resource content directly
- ostream.write(resourceBody);
+ source = new
ByteArrayInputStream(resourceBody);
}
+ OutputStreamWriter osw = new
OutputStreamWriter(ostream, charset);
+ PrintWriter pw = new PrintWriter(osw);
+ copy(resource, source, pw, fileEncoding);
+ pw.flush();
}
}
// If a stream was configured, it needs to be copied to
Modified: tomcat/trunk/test/org/apache/catalina/servlets/TestDefaultServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/servlets/TestDefaultServlet.java?rev=1800454&r1=1800453&r2=1800454&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/servlets/TestDefaultServlet.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/servlets/TestDefaultServlet.java Fri
Jun 30 20:29:51 2017
@@ -20,7 +20,9 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.io.StringReader;
import java.io.Writer;
+import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
@@ -29,6 +31,10 @@ import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.junit.Assert.assertEquals;
@@ -46,7 +52,9 @@ import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.SimpleHttpClient;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.http.parser.MediaType;
import org.apache.tomcat.websocket.server.WsContextListener;
public class TestDefaultServlet extends TomcatBaseTest {
@@ -622,4 +630,136 @@ public class TestDefaultServlet extends
return true;
}
}
+
+ @Test
+ public void testEncodingIncludeStreamOutIso88591() throws Exception {
+ doTestEncoding(false, "ISO-8859-1");
+ }
+
+ @Test
+ public void testEncodingIncludeWriterOutIso88591() throws Exception {
+ doTestEncoding(true, "ISO-8859-1");
+ }
+
+ @Test
+ public void testEncodingIncludeStreamOutUtf8() throws Exception {
+ doTestEncoding(false, "UTF-8");
+ }
+
+ @Test
+ public void testEncodingIncludeWriterOutUtf8() throws Exception {
+ doTestEncoding(true, "UTF-8");
+ }
+
+ @Test
+ public void testEncodingIncludeStreamOutIbm850() throws Exception {
+ doTestEncoding(false, "IBM850");
+ }
+
+ @Test
+ public void testEncodingIncludeWriterOutIbm850() throws Exception {
+ doTestEncoding(false, "IBM850");
+ }
+
+ public void doTestEncoding(boolean useWriter, String outputEncoding)
throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ File appDir = new File("test/webapp");
+
+ Context ctxt = tomcat.addContext("", appDir.getAbsolutePath());
+
+ Wrapper defaultServlet = Tomcat.addServlet(ctxt, "default",
DefaultServlet.class.getName());
+ defaultServlet.addInitParameter("fileEncoding", "IBM850");
+ ctxt.addServletMappingDecoded("/", "default");
+
+ Tomcat.addServlet(ctxt, "encoding",
+ new EncodingServlet(outputEncoding,
"/bug49nnn/bug49464-ibm850.txt", useWriter));
+ ctxt.addServletMappingDecoded("/test", "encoding");
+
+ tomcat.start();
+
+ final ByteChunk res = new ByteChunk();
+ Map<String,List<String>> headers = new HashMap<>();
+
+ int rc = getUrl("http://localhost:" + getPort() + "/test", res,
headers);
+
+ Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+ List<String> values = headers.get("Content-Type");
+ if (values.size() == 1) {
+ MediaType mediaType = MediaType.parseMediaType(new
StringReader(values.get(0)));
+ String charset = mediaType.getCharset();
+ if (charset == null) {
+ res.setCharset(StandardCharsets.ISO_8859_1);
+ } else {
+ res.setCharset(B2CConverter.getCharset(charset));
+ }
+ } else {
+ res.setCharset(StandardCharsets.ISO_8859_1);
+ }
+ Assert.assertEquals("½", res.toString());
+ }
+
+ @Test
+ public void testEncodingDirect() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ File appDir = new File("test/webapp");
+
+ Context ctxt = tomcat.addContext("", appDir.getAbsolutePath());
+
+ Wrapper defaultServlet = Tomcat.addServlet(ctxt, "default",
DefaultServlet.class.getName());
+ defaultServlet.addInitParameter("fileEncoding", "IBM850");
+ ctxt.addServletMappingDecoded("/", "default");
+
+ tomcat.start();
+
+ final ByteChunk res = new ByteChunk();
+ Map<String,List<String>> headers = new HashMap<>();
+
+ int rc = getUrl("http://localhost:" + getPort() +
"/bug49nnn/bug49464-ibm850.txt",
+ res, headers);
+
+ Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+ List<String> values = headers.get("Content-Type");
+ if (values != null && values.size() == 1) {
+ MediaType mediaType = MediaType.parseMediaType(new
StringReader(values.get(0)));
+ String charset = mediaType.getCharset();
+ if (charset == null) {
+ res.setCharset(StandardCharsets.ISO_8859_1);
+ } else {
+ res.setCharset(B2CConverter.getCharset(charset));
+ }
+ } else {
+ res.setCharset(StandardCharsets.ISO_8859_1);
+ }
+ Assert.assertEquals("½", res.toString());
+ }
+
+ private static class EncodingServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String outputEncoding;
+ private final String includeTarget;
+ private final boolean useWriter;
+
+ public EncodingServlet(String outputEncoding, String includeTarget,
boolean useWriter) {
+ this.outputEncoding = outputEncoding;
+ this.includeTarget = includeTarget;
+ this.useWriter = useWriter;
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ resp.setContentType("text/plain");
+ resp.setCharacterEncoding(outputEncoding);
+ if (useWriter) {
+ resp.getWriter();
+ }
+ resp.flushBuffer();
+ RequestDispatcher rd = req.getRequestDispatcher(includeTarget);
+ rd.include(req, resp);
+ }
+ }
}
Added: tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt?rev=1800454&view=auto
==============================================================================
--- tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt (added)
+++ tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt [IBM850] Fri Jun 30
20:29:51 2017
@@ -0,0 +1 @@
+½
\ No newline at end of file
Propchange: tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: tomcat/trunk/test/webapp/bug49nnn/bug49464-ibm850.txt
------------------------------------------------------------------------------
svn:mime-type = text/plain; charset="IBM850"
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1800454&r1=1800453&r2=1800454&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Jun 30 20:29:51 2017
@@ -48,6 +48,11 @@
<subsection name="Catalina">
<changelog>
<fix>
+ <bug>49464</bug>: Improve the Default Servlet's handling of static
files
+ when the file encoding is not compatible with the required response
+ encoding. (markt)
+ </fix>
+ <fix>
<bug>61214</bug>: Remove deleted attribute <code>servlets</code> from
the Context MBean description. Patch provided by Alexis Hassler.
(markt)
</fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]