Merge remote-tracking branch 'origin/jetty-8'
Conflicts: jetty-start/src/main/resources/org/eclipse/jetty/start/start.config jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java test-jetty-webapp/pom.xml tests/test-integration/pom.xml
This commit is contained in:
commit
8d0e776b2a
|
@ -24,6 +24,8 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* This rule can be used to protect against invalid unicode characters in a url making it into applications.
|
||||
|
@ -36,6 +38,8 @@ import org.eclipse.jetty.util.URIUtil;
|
|||
*/
|
||||
public class ValidUrlRule extends Rule
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ValidUrlRule.class);
|
||||
|
||||
String _code = "400";
|
||||
String _reason = "Illegal Url";
|
||||
|
||||
|
@ -72,12 +76,16 @@ public class ValidUrlRule extends Rule
|
|||
public String matchAndApply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
// best to decide the request uri and validate that
|
||||
// String uri = request.getRequestURI();
|
||||
String uri = URIUtil.decodePath(request.getRequestURI());
|
||||
|
||||
for (int i = 0; i < uri.length(); ++i)
|
||||
|
||||
for (int i = 0; i < uri.length();)
|
||||
{
|
||||
if (!isValidChar(uri.charAt(i)))
|
||||
int codepoint = uri.codePointAt(i);
|
||||
|
||||
if (!isValidChar(uri.codePointAt(i)))
|
||||
{
|
||||
|
||||
int code = Integer.parseInt(_code);
|
||||
|
||||
// status code 400 and up are error codes so include a reason
|
||||
|
@ -93,17 +101,20 @@ public class ValidUrlRule extends Rule
|
|||
// we have matched, return target and consider it is handled
|
||||
return target;
|
||||
}
|
||||
i += Character.charCount(codepoint);
|
||||
}
|
||||
|
||||
// we have not matched so return null
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isValidChar(char c)
|
||||
protected boolean isValidChar(int codepoint)
|
||||
{
|
||||
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
|
||||
Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint);
|
||||
|
||||
return (!Character.isISOControl(c)) && block != null && block != Character.UnicodeBlock.SPECIALS;
|
||||
LOG.debug("{} {} {} {}", Character.charCount(codepoint), codepoint, block, Character.isISOControl(codepoint));
|
||||
|
||||
return (!Character.isISOControl(codepoint)) && block != null && block != Character.UnicodeBlock.SPECIALS;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
|
|
|
@ -22,8 +22,10 @@ import static org.junit.Assert.assertEquals;
|
|||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ValidUrlRuleTest extends AbstractRuleTestCase
|
||||
{
|
||||
private ValidUrlRule _rule;
|
||||
|
@ -70,6 +72,46 @@ public class ValidUrlRuleTest extends AbstractRuleTestCase
|
|||
assertEquals("foo",_response.getReason());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidJsp() throws Exception
|
||||
{
|
||||
_rule.setCode("405");
|
||||
_rule.setReason("foo");
|
||||
_request.setRequestURI("/jsp/bean1.jsp%00");
|
||||
|
||||
String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
|
||||
|
||||
assertEquals(405,_response.getStatus());
|
||||
assertEquals("foo",_response.getReason());
|
||||
}
|
||||
|
||||
@Ignore("Not working in jetty-9")
|
||||
@Test
|
||||
public void testInvalidShamrock() throws Exception
|
||||
{
|
||||
_rule.setCode("405");
|
||||
_rule.setReason("foo");
|
||||
_request.setRequestURI("/jsp/shamrock-%00%E2%98%98.jsp");
|
||||
|
||||
String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
|
||||
|
||||
assertEquals(405,_response.getStatus());
|
||||
assertEquals("foo",_response.getReason());
|
||||
}
|
||||
|
||||
@Ignore("Not working in jetty-9")
|
||||
@Test
|
||||
public void testValidShamrock() throws Exception
|
||||
{
|
||||
_rule.setCode("405");
|
||||
_rule.setReason("foo");
|
||||
_request.setRequestURI("/jsp/shamrock-%E2%98%98.jsp");
|
||||
|
||||
String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
|
||||
|
||||
assertEquals(200,_response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCharacters() throws Exception
|
||||
{
|
||||
|
|
|
@ -128,8 +128,8 @@ $(jetty.home)/lib/jndi/** exists $(jetty.home)/lib/jndi
|
|||
$(jetty.home)/lib/jetty-jaas-${version}.jar ! available org.eclipse.jetty.jaas.JAASLoginService
|
||||
|
||||
[All,annotations]
|
||||
$(jetty.home)/lib/jetty-annotations-$(version).jar ! available org.eclipse.jetty.annotations.AnnotationFinder
|
||||
$(jetty.home)/lib/annotations/** exists $(jetty.home)/lib/jndi
|
||||
$(jetty.home)/lib/jetty-annotations-$(version).jar ! available org.eclipse.jetty.annotations.AnnotationParser
|
||||
$(jetty.home)/lib/annotations/** exists $(jetty.home)/lib/annotations
|
||||
|
||||
[All,setuid]
|
||||
$(jetty.home)/lib/jetty-setuid-$(version).jar ! available org.eclipse.jetty.setuid.SetUID
|
||||
|
|
|
@ -476,7 +476,7 @@ public class MultiPartInputStreamParser
|
|||
// Get first boundary
|
||||
String line=((ReadLineInputStream)_in).readLine();
|
||||
|
||||
if (line == null || line.length() == 0)
|
||||
if (line == null)
|
||||
throw new IOException("Missing content for multipart request");
|
||||
|
||||
boolean badFormatLogged = false;
|
||||
|
@ -492,7 +492,7 @@ public class MultiPartInputStreamParser
|
|||
line=(line==null?line:line.trim());
|
||||
}
|
||||
|
||||
if (line == null || line.length() == 0)
|
||||
if (line == null)
|
||||
throw new IOException("Missing initial multi part boundary");
|
||||
|
||||
// Read each part
|
||||
|
|
|
@ -89,6 +89,10 @@ public class FileResource extends URLResource
|
|||
// Try standard API to convert URL to file.
|
||||
_file =new File(new URI(url.toString()));
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FileResourceTest
|
||||
{
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
private URI createDummyFile(String name) throws IOException
|
||||
{
|
||||
File file = testdir.getFile(name);
|
||||
file.createNewFile();
|
||||
return file.toURI();
|
||||
}
|
||||
|
||||
private URL decode(URL url) throws MalformedURLException
|
||||
{
|
||||
String raw = url.toExternalForm();
|
||||
String decoded = UrlEncoded.decodeString(raw,0,raw.length(),StringUtil.__UTF8_CHARSET);
|
||||
return new URL(decoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExist_Normal() throws Exception
|
||||
{
|
||||
createDummyFile("a.jsp");
|
||||
|
||||
URI ref = testdir.getDir().toURI().resolve("a.jsp");
|
||||
FileResource fileres = new FileResource(decode(ref.toURL()));
|
||||
Assert.assertThat("FileResource: " + fileres,fileres.exists(),is(true));
|
||||
}
|
||||
|
||||
@Ignore("Cannot get null to be seen by FileResource")
|
||||
@Test
|
||||
public void testExist_BadNull() throws Exception
|
||||
{
|
||||
createDummyFile("a.jsp");
|
||||
|
||||
try {
|
||||
// request with null at end
|
||||
URI ref = testdir.getDir().toURI().resolve("a.jsp%00");
|
||||
FileResource fileres = new FileResource(decode(ref.toURL()));
|
||||
Assert.assertThat("FileResource: " + fileres,fileres.exists(),is(false));
|
||||
} catch(URISyntaxException e) {
|
||||
// Valid path
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Validation shouldn't be done in FileResource")
|
||||
@Test
|
||||
public void testExist_BadNullX() throws Exception
|
||||
{
|
||||
createDummyFile("a.jsp");
|
||||
|
||||
try {
|
||||
// request with null and x at end
|
||||
URI ref = testdir.getDir().toURI().resolve("a.jsp%00x");
|
||||
FileResource fileres = new FileResource(decode(ref.toURL()));
|
||||
Assert.assertThat("FileResource: " + fileres,fileres.exists(),is(false));
|
||||
} catch(URISyntaxException e) {
|
||||
// Valid path
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,6 +77,13 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkMode>always</forkMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
|
@ -100,11 +107,26 @@
|
|||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-webapp-rfc2616</artifactId>
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.test.jsp;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.jasper.servlet.JspServlet;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JspMatchingTest
|
||||
{
|
||||
private static Server server;
|
||||
private static URI serverURI;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
connector.setPort(0);
|
||||
server.addConnector(connector);
|
||||
|
||||
// Configure LoginService
|
||||
HashLoginService login = new HashLoginService();
|
||||
login.setName("Test Realm");
|
||||
File realmFile = MavenTestingUtils.getTestResourceFile("realm.properties");
|
||||
login.setConfig(realmFile.getAbsolutePath());
|
||||
server.addBean(login);
|
||||
|
||||
// Configure WebApp
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/");
|
||||
File webappBase = MavenTestingUtils.getTestResourceDir("docroots/jsp");
|
||||
context.setResourceBase(webappBase.getAbsolutePath());
|
||||
context.setClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
// add default servlet
|
||||
ServletHolder defaultServHolder = context.addServlet(DefaultServlet.class,"/");
|
||||
defaultServHolder.setInitParameter("aliases","true"); // important!
|
||||
|
||||
// add jsp
|
||||
ServletHolder jsp = context.addServlet(JspServlet.class,"*.jsp");
|
||||
jsp.setInitParameter("classpath",context.getClassPath());
|
||||
|
||||
// add context
|
||||
server.setHandler(context);
|
||||
|
||||
server.start();
|
||||
|
||||
serverURI = new URI("http://localhost:" + connector.getLocalPort() + "/");
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanRef() throws Exception
|
||||
{
|
||||
|
||||
URI uri = serverURI.resolve("/dump.jsp");
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
try
|
||||
{
|
||||
conn = (HttpURLConnection)uri.toURL().openConnection();
|
||||
conn.setConnectTimeout(1000);
|
||||
conn.setReadTimeout(1000);
|
||||
Assert.assertThat(conn.getResponseCode(),is(200));
|
||||
|
||||
// make sure that jsp actually ran, and didn't just get passed onto
|
||||
// the default servlet to return the jsp source
|
||||
String body = getResponseBody(conn);
|
||||
Assert.assertThat("Body",body,not(containsString("<%@")));
|
||||
Assert.assertThat("Body",body,not(containsString("<jsp:")));
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeanRefInvalid_null() throws Exception
|
||||
{
|
||||
|
||||
URI uri = serverURI.resolve("/dump.jsp%00");
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
try
|
||||
{
|
||||
conn = (HttpURLConnection)uri.toURL().openConnection();
|
||||
conn.setConnectTimeout(1000);
|
||||
conn.setReadTimeout(1000);
|
||||
Assert.assertThat("Response Code",conn.getResponseCode(),is(404));
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("DefaultServlet + aliasing breaks this test ATM")
|
||||
@Test
|
||||
public void testGetBeanRefInvalid_nullx() throws Exception
|
||||
{
|
||||
|
||||
URI uri = serverURI.resolve("/dump.jsp%00x");
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
try
|
||||
{
|
||||
conn = (HttpURLConnection)uri.toURL().openConnection();
|
||||
conn.setConnectTimeout(1000);
|
||||
conn.setReadTimeout(1000);
|
||||
Assert.assertThat("Response Code",conn.getResponseCode(),is(404));
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("DefaultServlet + aliasing breaks this test ATM")
|
||||
@Test
|
||||
public void testGetBeanRefInvalid_nullslash() throws Exception
|
||||
{
|
||||
|
||||
URI uri = serverURI.resolve("/dump.jsp%00/");
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
try
|
||||
{
|
||||
conn = (HttpURLConnection)uri.toURL().openConnection();
|
||||
conn.setConnectTimeout(1000);
|
||||
conn.setReadTimeout(1000);
|
||||
Assert.assertThat("Response Code",conn.getResponseCode(),is(404));
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("DefaultServlet + aliasing breaks this test ATM")
|
||||
@Test
|
||||
public void testGetBeanRefInvalid_nullxslash() throws Exception
|
||||
{
|
||||
|
||||
URI uri = serverURI.resolve("/dump.jsp%00x/");
|
||||
|
||||
HttpURLConnection conn = null;
|
||||
try
|
||||
{
|
||||
conn = (HttpURLConnection)uri.toURL().openConnection();
|
||||
conn.setConnectTimeout(1000);
|
||||
conn.setReadTimeout(1000);
|
||||
Assert.assertThat("Response Code",conn.getResponseCode(),is(404));
|
||||
}
|
||||
finally
|
||||
{
|
||||
close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getResponseBody(HttpURLConnection conn) throws IOException
|
||||
{
|
||||
InputStream in = null;
|
||||
try
|
||||
{
|
||||
in = conn.getInputStream();
|
||||
return IO.toString(in);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.close(in);
|
||||
}
|
||||
}
|
||||
|
||||
private void close(HttpURLConnection conn)
|
||||
{
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<html><head>
|
||||
<%@ page import="java.util.Enumeration" %>
|
||||
</head><body>
|
||||
<h1>JSP Dump</h1>
|
||||
|
||||
<table border="1">
|
||||
<tr><th>Request URI:</th><td><%= request.getRequestURI() %></td></tr>
|
||||
<tr><th>ServletPath:</th><td><%= request.getServletPath() %></td></tr>
|
||||
<tr><th>PathInfo:</th><td><%= request.getPathInfo() %></td></tr>
|
||||
|
||||
<%
|
||||
Enumeration e =request.getParameterNames();
|
||||
while(e.hasMoreElements())
|
||||
{
|
||||
String name = (String)e.nextElement();
|
||||
%>
|
||||
<tr>
|
||||
<th>getParameter("<%= name %>")</th>
|
||||
<td><%= request.getParameter(name) %></td></tr>
|
||||
<% } %>
|
||||
|
||||
</table>
|
||||
</body></html>
|
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# This file defines users passwords and roles for a HashUserRealm
|
||||
#
|
||||
# The format is
|
||||
# <username>: <password>[,<rolename> ...]
|
||||
#
|
||||
# Passwords may be clear text, obfuscated or checksummed. The class
|
||||
# org.eclipse.util.Password should be used to generate obfuscated
|
||||
# passwords or password checksums
|
||||
#
|
||||
# If DIGEST Authentication is used, the password must be in a recoverable
|
||||
# format, either plain text or OBF:.
|
||||
#
|
||||
jetty: MD5:164c88b302622e17050af52c89945d44,user
|
||||
admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin
|
||||
other: OBF:1xmk1w261u9r1w1c1xmq,user
|
||||
plain: plain,user
|
||||
user: password,user
|
||||
|
||||
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
|
||||
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
|
Loading…
Reference in New Issue