Merge remote-tracking branch 'origin/jetty-9.2.x'

Conflicts:
	jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
	jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
	jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
This commit is contained in:
Greg Wilkins 2015-05-29 21:05:26 +10:00
commit 69bf5ab46c
8 changed files with 109 additions and 75 deletions

View File

@ -29,7 +29,9 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.sun.net.httpserver.Authenticator; import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.Authenticator.Result; import com.sun.net.httpserver.Authenticator.Result;
@ -43,6 +45,7 @@ import com.sun.net.httpserver.HttpPrincipal;
*/ */
public class HttpSpiContextHandler extends ContextHandler public class HttpSpiContextHandler extends ContextHandler
{ {
public static final Logger LOG = Log.getLogger(HttpSpiContextHandler.class);
private HttpContext _httpContext; private HttpContext _httpContext;
@ -88,16 +91,20 @@ public class HttpSpiContextHandler extends ContextHandler
} }
catch (Exception ex) catch (Exception ex)
{ {
LOG.debug(ex);
PrintWriter writer = new PrintWriter(jettyHttpExchange.getResponseBody()); PrintWriter writer = new PrintWriter(jettyHttpExchange.getResponseBody());
resp.setStatus(500); resp.setStatus(500);
writer.println("<h2>HTTP ERROR: 500</h2>"); writer.println("<h2>HTTP ERROR: 500</h2>");
writer.println("<pre>INTERNAL_SERVER_ERROR</pre>"); writer.println("<pre>INTERNAL_SERVER_ERROR</pre>");
writer.println("<p>RequestURI=" + req.getRequestURI() + "</p>"); writer.println("<p>RequestURI=" + StringUtil.sanitizeXmlString(req.getRequestURI()) + "</p>");
writer.println("<pre>"); if (LOG.isDebugEnabled())
ex.printStackTrace(writer); {
writer.println("</pre>"); writer.println("<pre>");
ex.printStackTrace(writer);
writer.println("</pre>");
}
baseRequest.getHttpChannel().getHttpConfiguration().writePoweredBy(writer,"<p>","</p>"); baseRequest.getHttpChannel().getHttpConfiguration().writePoweredBy(writer,"<p>","</p>");

View File

@ -577,19 +577,9 @@ public class Response implements HttpServletResponse
setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString()); setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString());
try (ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);) try (ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);)
{ {
if (message != null) message=StringUtil.sanitizeXmlString(message);
{
message= StringUtil.replace(message, "&", "&amp;");
message= StringUtil.replace(message, "<", "&lt;");
message= StringUtil.replace(message, ">", "&gt;");
}
String uri= request.getRequestURI(); String uri= request.getRequestURI();
if (uri!=null) uri=StringUtil.sanitizeXmlString(uri);
{
uri= StringUtil.replace(uri, "&", "&amp;");
uri= StringUtil.replace(uri, "<", "&lt;");
uri= StringUtil.replace(uri, ">", "&gt;");
}
writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n"); writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
writer.write("<title>Error "); writer.write("<title>Error ");

View File

@ -40,6 +40,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.ByteArrayISO8859Writer; import org.eclipse.jetty.util.ByteArrayISO8859Writer;
import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -278,29 +279,7 @@ public class ErrorHandler extends AbstractHandler
if (string==null) if (string==null)
return; return;
for (int i=0;i<string.length();i++) writer.write(StringUtil.sanitizeXmlString(string));
{
char c=string.charAt(i);
switch(c)
{
case '&' :
writer.write("&amp;");
break;
case '<' :
writer.write("&lt;");
break;
case '>' :
writer.write("&gt;");
break;
default:
if (Character.isISOControl(c) && !Character.isWhitespace(c))
writer.write('?');
else
writer.write(c);
}
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -746,6 +746,74 @@ public class StringUtil
return s.substring(1,s.length()-1).split(" *, *"); return s.substring(1,s.length()-1).split(" *, *");
} }
public static String sanitizeXmlString(String html)
{
if (html==null)
return null;
int i=0;
// Are there any characters that need sanitizing?
loop: for (;i<html.length();i++)
{
char c=html.charAt(i);
switch(c)
{
case '&' :
case '<' :
case '>' :
case '\'':
case '"':
break loop;
default:
if (Character.isISOControl(c) && !Character.isWhitespace(c))
break loop;
}
}
// No characters need sanitizing, so return original string
if (i==html.length())
return html;
// Create builder with OK content so far
StringBuilder out = new StringBuilder(html.length()*4/3);
out.append(html,0,i);
// sanitize remaining content
for (;i<html.length();i++)
{
char c=html.charAt(i);
switch(c)
{
case '&' :
out.append("&amp;");
break;
case '<' :
out.append("&lt;");
break;
case '>' :
out.append("&gt;");
break;
case '\'':
out.append("&apos;");
break;
case '"':
out.append("&quot;");
break;
default:
if (Character.isISOControl(c) && !Character.isWhitespace(c))
out.append('?');
else
out.append(c);
}
}
return out.toString();
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** The String value of an Object /** The String value of an Object

View File

@ -660,7 +660,7 @@ public abstract class Resource implements ResourceFactory, Closeable
private static String deTag(String raw) private static String deTag(String raw)
{ {
return StringUtil.replace( StringUtil.replace(raw,"<","&lt;"), ">", "&gt;"); return StringUtil.sanitizeXmlString(raw);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -201,7 +201,8 @@ public class StringUtilTest
} }
@Test @Test
public void testIsBlank() { public void testIsBlank()
{
Assert.assertTrue(StringUtil.isBlank(null)); Assert.assertTrue(StringUtil.isBlank(null));
Assert.assertTrue(StringUtil.isBlank("")); Assert.assertTrue(StringUtil.isBlank(""));
Assert.assertTrue(StringUtil.isBlank("\r\n")); Assert.assertTrue(StringUtil.isBlank("\r\n"));
@ -216,7 +217,8 @@ public class StringUtilTest
} }
@Test @Test
public void testIsNotBlank() { public void testIsNotBlank()
{
Assert.assertFalse(StringUtil.isNotBlank(null)); Assert.assertFalse(StringUtil.isNotBlank(null));
Assert.assertFalse(StringUtil.isNotBlank("")); Assert.assertFalse(StringUtil.isNotBlank(""));
Assert.assertFalse(StringUtil.isNotBlank("\r\n")); Assert.assertFalse(StringUtil.isNotBlank("\r\n"));
@ -229,4 +231,14 @@ public class StringUtilTest
Assert.assertTrue(StringUtil.isNotBlank(".")); Assert.assertTrue(StringUtil.isNotBlank("."));
Assert.assertTrue(StringUtil.isNotBlank(";\n")); Assert.assertTrue(StringUtil.isNotBlank(";\n"));
} }
@Test
public void testSanitizeHTML()
{
assertEquals(null,StringUtil.sanitizeXmlString(null));
assertEquals("",StringUtil.sanitizeXmlString(""));
assertEquals("&lt;&amp;&gt;",StringUtil.sanitizeXmlString("<&>"));
assertEquals("Hello &lt;Cruel&gt; World",StringUtil.sanitizeXmlString("Hello <Cruel> World"));
assertEquals("Hello ? World",StringUtil.sanitizeXmlString("Hello \u0000 World"));
}
} }

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -526,7 +527,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
/** /**
* Upgrade the request/response to a WebSocket Connection. * Upgrade the request/response to a WebSocket Connection.
* <p> * <p/>
* This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the * This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the
* connection. * connection.
* *
@ -568,7 +569,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
} }
else else
{ {
warn.append('"').append(ua.replaceAll("<", "&lt;")).append("\" "); warn.append('"').append(StringUtil.sanitizeXmlString(ua)).append("\" ");
} }
warn.append("requested WebSocket version [").append(version); warn.append("requested WebSocket version [").append(version);
warn.append("], Jetty supports version"); warn.append("], Jetty supports version");

View File

@ -25,6 +25,8 @@ import java.io.OutputStreamWriter;
import java.util.Map; import java.util.Map;
import java.util.Stack; import java.util.Stack;
import org.eclipse.jetty.util.StringUtil;
public class XmlAppendable public class XmlAppendable
{ {
private final String SPACES=" "; private final String SPACES=" ";
@ -82,32 +84,7 @@ public class XmlAppendable
public XmlAppendable content(String s) throws IOException public XmlAppendable content(String s) throws IOException
{ {
if (s!=null) if (s!=null)
{ _out.append(StringUtil.sanitizeXmlString(s));
for (int i=0;i<s.length();i++)
{
char c = s.charAt(i);
switch(c)
{
case '<':
_out.append("&lt;");
break;
case '>':
_out.append("&gt;");
break;
case '&':
_out.append("&amp;");
break;
case '\'':
_out.append("&apos;");
break;
case '"':
_out.append("&quot;");
break;
default:
_out.append(c);
}
}
}
return this; return this;
} }