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.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.Result;
@ -43,6 +45,7 @@ import com.sun.net.httpserver.HttpPrincipal;
*/
public class HttpSpiContextHandler extends ContextHandler
{
public static final Logger LOG = Log.getLogger(HttpSpiContextHandler.class);
private HttpContext _httpContext;
@ -88,16 +91,20 @@ public class HttpSpiContextHandler extends ContextHandler
}
catch (Exception ex)
{
LOG.debug(ex);
PrintWriter writer = new PrintWriter(jettyHttpExchange.getResponseBody());
resp.setStatus(500);
writer.println("<h2>HTTP ERROR: 500</h2>");
writer.println("<pre>INTERNAL_SERVER_ERROR</pre>");
writer.println("<p>RequestURI=" + req.getRequestURI() + "</p>");
writer.println("<p>RequestURI=" + StringUtil.sanitizeXmlString(req.getRequestURI()) + "</p>");
if (LOG.isDebugEnabled())
{
writer.println("<pre>");
ex.printStackTrace(writer);
writer.println("</pre>");
}
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());
try (ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);)
{
if (message != null)
{
message= StringUtil.replace(message, "&", "&amp;");
message= StringUtil.replace(message, "<", "&lt;");
message= StringUtil.replace(message, ">", "&gt;");
}
message=StringUtil.sanitizeXmlString(message);
String uri= request.getRequestURI();
if (uri!=null)
{
uri= StringUtil.replace(uri, "&", "&amp;");
uri= StringUtil.replace(uri, "<", "&lt;");
uri= StringUtil.replace(uri, ">", "&gt;");
}
uri=StringUtil.sanitizeXmlString(uri);
writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
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.ByteArrayISO8859Writer;
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;
@ -278,29 +279,7 @@ public class ErrorHandler extends AbstractHandler
if (string==null)
return;
for (int i=0;i<string.length();i++)
{
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);
}
}
writer.write(StringUtil.sanitizeXmlString(string));
}
/* ------------------------------------------------------------ */

View File

@ -746,6 +746,74 @@ public class StringUtil
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

View File

@ -660,7 +660,7 @@ public abstract class Resource implements ResourceFactory, Closeable
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
public void testIsBlank() {
public void testIsBlank()
{
Assert.assertTrue(StringUtil.isBlank(null));
Assert.assertTrue(StringUtil.isBlank(""));
Assert.assertTrue(StringUtil.isBlank("\r\n"));
@ -216,7 +217,8 @@ public class StringUtilTest
}
@Test
public void testIsNotBlank() {
public void testIsNotBlank()
{
Assert.assertFalse(StringUtil.isNotBlank(null));
Assert.assertFalse(StringUtil.isNotBlank(""));
Assert.assertFalse(StringUtil.isNotBlank("\r\n"));
@ -229,4 +231,14 @@ public class StringUtilTest
Assert.assertTrue(StringUtil.isNotBlank("."));
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.servlet.ServletContextHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
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.
* <p>
* <p/>
* This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the
* connection.
*
@ -568,7 +569,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
}
else
{
warn.append('"').append(ua.replaceAll("<", "&lt;")).append("\" ");
warn.append('"').append(StringUtil.sanitizeXmlString(ua)).append("\" ");
}
warn.append("requested WebSocket version [").append(version);
warn.append("], Jetty supports version");

View File

@ -25,6 +25,8 @@ import java.io.OutputStreamWriter;
import java.util.Map;
import java.util.Stack;
import org.eclipse.jetty.util.StringUtil;
public class XmlAppendable
{
private final String SPACES=" ";
@ -82,32 +84,7 @@ public class XmlAppendable
public XmlAppendable content(String s) throws IOException
{
if (s!=null)
{
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);
}
}
}
_out.append(StringUtil.sanitizeXmlString(s));
return this;
}