From c2831bf09ccc346436157f34452d7addc82d7870 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 1 Jun 2016 15:28:04 +1000 Subject: [PATCH] Issue #608 reset encoding set from content type Use an enum to track where a content encoding came from and selectively clear/reset --- .../org/eclipse/jetty/server/Response.java | 49 ++++++++++++++----- .../eclipse/jetty/server/ResponseTest.java | 34 ++++++++++++- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index a119190a752..ee7f42aa795 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -24,6 +24,7 @@ import java.nio.channels.IllegalSelectorException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.Enumeration; import java.util.Iterator; import java.util.Locale; @@ -108,12 +109,15 @@ public class Response implements HttpServletResponse private Locale _locale; private MimeTypes.Type _mimeType; private String _characterEncoding; - private boolean _explicitEncoding; + private EncodingFrom _encodingFrom=EncodingFrom.NOT_SET; private String _contentType; private OutputType _outputType = OutputType.NONE; private ResponseWriter _writer; private long _contentLength = -1; + private enum EncodingFrom { NOT_SET, INFERRED, SET_LOCALE, SET_CONTENT_TYPE, SET_CHARACTER_ENCODING }; + private static final EnumSet __localeOverride = EnumSet.of(EncodingFrom.NOT_SET,EncodingFrom.INFERRED); + public Response(HttpChannel channel, HttpOutput out) { @@ -138,7 +142,7 @@ public class Response implements HttpServletResponse _contentLength = -1; _out.recycle(); _fields.clear(); - _explicitEncoding=false; + _encodingFrom=EncodingFrom.NOT_SET; } public HttpOutput getHttpOutput() @@ -899,7 +903,7 @@ public class Response implements HttpServletResponse encoding = MimeTypes.inferCharsetFromContentType(_contentType); if (encoding == null) encoding = StringUtil.__ISO_8859_1; - setCharacterEncoding(encoding,false); + setCharacterEncoding(encoding,EncodingFrom.INFERRED); } } @@ -1015,10 +1019,10 @@ public class Response implements HttpServletResponse @Override public void setCharacterEncoding(String encoding) { - setCharacterEncoding(encoding,true); + setCharacterEncoding(encoding,EncodingFrom.SET_CHARACTER_ENCODING); } - private void setCharacterEncoding(String encoding, boolean explicit) + private void setCharacterEncoding(String encoding, EncodingFrom from) { if (isIncluding() || isWriting()) return; @@ -1027,7 +1031,7 @@ public class Response implements HttpServletResponse { if (encoding == null) { - _explicitEncoding=false; + _encodingFrom=EncodingFrom.NOT_SET; // Clear any encoding. if (_characterEncoding != null) @@ -1050,7 +1054,7 @@ public class Response implements HttpServletResponse else { // No, so just add this one to the mimetype - _explicitEncoding = explicit; + _encodingFrom = from; _characterEncoding = HttpGenerator.__STRICT?encoding:StringUtil.normalizeCharset(encoding); if (_mimeType!=null) { @@ -1100,10 +1104,29 @@ public class Response implements HttpServletResponse if (charset == null) { - if (_characterEncoding != null) + switch (_encodingFrom) { - _contentType = contentType + ";charset=" + _characterEncoding; - _mimeType = null; + case NOT_SET: + break; + case INFERRED: + case SET_CONTENT_TYPE: + if (isWriting()) + { + _mimeType=null; + _contentType = _contentType + ";charset=" + _characterEncoding; + } + else + { + _encodingFrom=EncodingFrom.NOT_SET; + _characterEncoding=null; + } + break; + case SET_LOCALE: + case SET_CHARACTER_ENCODING: + { + _contentType = contentType + ";charset=" + _characterEncoding; + _mimeType = null; + } } } else if (isWriting() && !charset.equalsIgnoreCase(_characterEncoding)) @@ -1117,7 +1140,7 @@ public class Response implements HttpServletResponse else { _characterEncoding = charset; - _explicitEncoding = true; + _encodingFrom = EncodingFrom.SET_CONTENT_TYPE; } if (HttpGenerator.__STRICT || _mimeType==null) @@ -1268,8 +1291,8 @@ public class Response implements HttpServletResponse String charset = _channel.getRequest().getContext().getContextHandler().getLocaleEncoding(locale); - if (charset != null && charset.length() > 0 && !_explicitEncoding) - setCharacterEncoding(charset,false); + if (charset != null && charset.length() > 0 && __localeOverride.contains(_encodingFrom)) + setCharacterEncoding(charset,EncodingFrom.SET_LOCALE); } @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index fc7d19e0e58..58500fc4dd4 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -165,7 +165,7 @@ public class ResponseTest assertEquals("text/html", response.getContentType()); response.getWriter(); assertEquals("text/html;charset=utf-8", response.getContentType()); - response.setContentType("foo2/bar2"); + response.setContentType("foo2/bar2;charset=utf-8"); assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); response.recycle(); @@ -357,6 +357,38 @@ public class ResponseTest assertEquals("text/xml;charset=utf-8", response.getContentType()); } + @Test + public void testResetContentTypeWithoutCharacterEncoding() throws Exception + { + Response response = newResponse(); + + response.setCharacterEncoding("utf-8"); + response.setContentType("wrong/answer"); + response.setContentType("foo/bar"); + assertEquals("foo/bar;charset=utf-8", response.getContentType()); + response.getWriter(); + response.setContentType("foo2/bar2"); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); + } + + + @Test + public void testResetContentTypeWithCharacterEncoding() throws Exception + { + Response response = newResponse(); + + response.setContentType("wrong/answer;charset=utf-8"); + response.setContentType("foo/bar"); + assertEquals("foo/bar", response.getContentType()); + response.setContentType("wrong/answer;charset=utf-8"); + response.getWriter(); + response.setContentType("foo2/bar2;charset=utf-16"); + assertEquals("foo2/bar2;charset=utf-8", response.getContentType()); + } + + + + @Test public void testContentTypeWithOther() throws Exception {