Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project

Conflicts:
	jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherTest.java
This commit is contained in:
Joakim Erdfelt 2015-04-29 18:12:04 -07:00
commit 37738d15e5
20 changed files with 196 additions and 128 deletions

View File

@ -1,5 +1,6 @@
jetty-9.3.0-SNAPSHOT
jetty-9.2.11.M0 - 25 March 2015
+ 454934 WebSocketClient / connectToServer can block indefinitely during
upgrade failure

View File

@ -76,7 +76,7 @@ public enum HttpMethod
return HEAD;
break;
case 'O':
if (bytes[position+1]=='O' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 &&
if (bytes[position+1]=='P' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 &&
bytes[position+4]=='O' && bytes[position+5]=='N' && bytes[position+6]=='S' && bytes[position+7]==' ' )
return OPTIONS;
break;

View File

@ -71,8 +71,7 @@ public class JettyEffectiveWebXml extends JettyRunMojo
@Override
public void startJetty() throws MojoExecutionException
{
//Only do enough setup to be able to produce a quickstart-web.xml file to
//pass onto the forked process to run
//Only do enough setup to be able to produce a quickstart-web.xml file
//if the user didn't nominate a file to generate into, pick the name and
//make sure that it is deleted on exit

View File

@ -146,6 +146,7 @@ public class JettyRunForkedMojo extends JettyRunMojo
private Resource originalBaseResource;
private boolean originalPersistTemp;
/**
@ -253,6 +254,9 @@ public class JettyRunForkedMojo extends JettyRunMojo
//copy the base resource as configured by the plugin
originalBaseResource = webApp.getBaseResource();
//get the original persistance setting
originalPersistTemp = webApp.isPersistTempDirectory();
//set the webapp up to do very little other than generate the quickstart-web.xml
webApp.setCopyWebDir(false);
webApp.setCopyWebInf(false);
@ -275,8 +279,11 @@ public class JettyRunForkedMojo extends JettyRunMojo
tpool.start();
else
webApp.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE.toString());
//leave everything unpacked for the forked process to use
webApp.setPersistTempDirectory(true);
webApp.start(); //just enough to generate the quickstart
webApp.start(); //just enough to generate the quickstart
//save config of the webapp BEFORE we stop
File props = prepareConfiguration();
@ -470,31 +477,23 @@ public class JettyRunForkedMojo extends JettyRunMojo
//tmp dir
props.put("tmp.dir", webApp.getTempDirectory().getAbsolutePath());
props.put("tmp.dir.persist", Boolean.toString(webApp.isPersistTempDirectory()));
props.put("tmp.dir.persist", Boolean.toString(originalPersistTemp));
//send over the original base resources before any overlays were added
if (originalBaseResource instanceof ResourceCollection)
props.put("base.dirs.orig", toCSV(((ResourceCollection)originalBaseResource).getResources()));
else
props.put("base.dirs.orig", originalBaseResource.toString());
//send over the calculated resource bases that includes unpacked overlays, but none of the
//meta-inf resources
Resource postOverlayResources = (Resource)webApp.getAttribute(MavenWebInfConfiguration.RESOURCE_BASES_POST_OVERLAY);
if (postOverlayResources instanceof ResourceCollection)
props.put("base.dirs", toCSV(((ResourceCollection)postOverlayResources).getResources()));
else
props.put("base.dirs", postOverlayResources.toString());
//resource bases - these are what has been configured BEFORE the webapp started and
//potentially reordered them and included any resources from META-INF
if (originalBaseResource != null)
{
StringBuffer rb = new StringBuffer();
if (originalBaseResource instanceof ResourceCollection)
{
ResourceCollection resources = ((ResourceCollection)originalBaseResource);
for (Resource r:resources.getResources())
{
if (rb.length() > 0) rb.append(",");
rb.append(r.toString());
}
}
else
rb.append(originalBaseResource.toString());
props.put("base.dirs", rb.toString());
}
//sort out the resource base directories of the webapp
props.put("base.first", Boolean.toString(webApp.getBaseAppFirst()));
//web-inf classes
if (webApp.getClasses() != null)
{
@ -751,4 +750,17 @@ public class JettyRunForkedMojo extends JettyRunMojo
}
return strbuff.toString();
}
private String toCSV (Resource[] resources)
{
StringBuffer rb = new StringBuffer();
for (Resource r:resources)
{
if (rb.length() > 0) rb.append(",");
rb.append(r.toString());
}
return rb.toString();
}
}

View File

@ -23,9 +23,11 @@ import java.io.File;
import java.util.Iterator;
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
@ -54,6 +56,20 @@ public class MavenQuickStartConfiguration extends QuickStartConfiguration
return _quickStartWebXml;
}
@Override
public void preConfigure(WebAppContext context) throws Exception
{
//check that webapp is suitable for quick start
if (context.getBaseResource() == null)
throw new IllegalStateException ("No location for webapp");
//look for quickstart-web.xml in WEB-INF of webapp
Resource quickStartWebXml = getQuickStartWebXml(context);
LOG.debug("quickStartWebXml={}",quickStartWebXml);
context.getMetaData().setWebXml(quickStartWebXml);
}
@Override
@ -89,4 +105,28 @@ public class MavenQuickStartConfiguration extends QuickStartConfiguration
context.setServerClasses( newServerClasses );
}
@Override
public void deconfigure(WebAppContext context) throws Exception
{
//if we're not persisting the temp dir, get rid of any overlays
if (!context.isPersistTempDirectory())
{
Resource originalBases = (Resource)context.getAttribute("org.eclipse.jetty.resources.originalBases");
String originalBaseStr = originalBases.toString();
//Iterate over all of the resource bases and ignore any that were original bases, just
//deleting the overlays
Resource res = context.getBaseResource();
if (res instanceof ResourceCollection)
{
for (Resource r:((ResourceCollection)res).getResources())
{
if (originalBaseStr.contains(r.toString()))
continue;
IO.delete(r.getFile());
}
}
}
}
}

View File

@ -25,7 +25,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -46,7 +46,7 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
{
private static final Logger LOG = Log.getLogger(MavenWebInfConfiguration.class);
public static final String RESOURCE_BASES_POST_OVERLAY = "org.eclipse.jetty.resource.postOverlay";
protected static int COUNTER = 0;
protected Resource _originalResourceBase;
protected List<Resource> _unpackedOverlayResources;
@ -115,24 +115,11 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
*/
public void deconfigure(WebAppContext context) throws Exception
{
//remove the unpacked wars
if (_unpackedOverlayResources != null && !_unpackedOverlayResources.isEmpty())
{
try
{
for (Resource r:_unpackedOverlayResources)
{
IO.delete(r.getFile());
}
}
catch (IOException e)
{
LOG.ignore(e);
}
}
super.deconfigure(context);
//restore whatever the base resource was before we might have included overlaid wars
context.setBaseResource(_originalResourceBase);
//undo the setting of the overlayed resources
context.removeAttribute(RESOURCE_BASES_POST_OVERLAY);
}
@ -190,9 +177,10 @@ public class MavenWebInfConfiguration extends WebInfConfiguration
resourceBaseCollection.add(_originalResourceBase);
}
}
jwac.setBaseResource(new ResourceCollection(resourceBaseCollection.toArray(new Resource[resourceBaseCollection.size()])));
}
jwac.setAttribute(RESOURCE_BASES_POST_OVERLAY, jwac.getBaseResource());
}

View File

@ -192,21 +192,23 @@ public class Starter
str = (String)props.getProperty("tmp.dir.persist");
if (str != null)
webApp.setPersistTempDirectory(Boolean.valueOf(str));
// - the base directories
//Get the calculated base dirs which includes the overlays
str = (String)props.getProperty("base.dirs");
if (str != null && !"".equals(str.trim()))
{
ResourceCollection bases = new ResourceCollection(str.split(","));
webApp.setWar(bases.getResources()[0].toString());
webApp.setWar(null);
webApp.setBaseResource(bases);
}
// - put virtual webapp base resource first on resource path or not
str = (String)props.getProperty("base.first");
//Get the original base dirs without the overlays
str = (String)props.get("base.dirs.orig");
if (str != null && !"".equals(str.trim()))
webApp.setBaseAppFirst(Boolean.valueOf(str));
{
ResourceCollection bases = new ResourceCollection(str.split(","));
webApp.setAttribute ("org.eclipse.jetty.resources.originalBases", bases);
}
//For overlays
str = (String)props.getProperty("maven.war.includes");

View File

@ -26,13 +26,14 @@ import java.util.Locale;
import javax.servlet.ServletResponse;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/**
/** Specialized PrintWriter for servlet Responses
* <p>An instance of ResponseWriter is the {@link PrintWriter} subclass returned by {@link Response#getWriter()}.
* It differs from the standard {@link PrintWriter} in that:<ul>
* <li>It does not support autoflush</li>
@ -42,7 +43,7 @@ import org.eclipse.jetty.util.log.Logger;
* </ul>
*
*/
class ResponseWriter extends PrintWriter
public class ResponseWriter extends PrintWriter
{
private static final Logger LOG = Log.getLogger(ResponseWriter.class);
private final static String __lineSeparator = System.getProperty("line.separator");
@ -132,7 +133,7 @@ class ResponseWriter extends PrintWriter
throw new RuntimeIOException(_ioException);
if (_isClosed)
throw new IOException("Stream closed");
throw new EofException("Stream closed");
}
@Override

View File

@ -500,8 +500,10 @@ public class Server extends HandlerWrapper implements Attributes
if (LOG.isDebugEnabled())
LOG.debug("{} on {}{}",request.getDispatcherType(),connection,"\n"+request.getMethod()+" "+request.getHttpURI()+"\n"+request.getHttpFields());
if ("*".equals(target))
if (HttpMethod.OPTIONS.is(request.getMethod()) || "*".equals(target))
{
if (!HttpMethod.OPTIONS.is(request.getMethod()))
response.sendError(HttpStatus.BAD_REQUEST_400);
handleOptions(request,response);
if (!request.isHandled())
handle(target, request, request, response);
@ -518,12 +520,6 @@ public class Server extends HandlerWrapper implements Attributes
*/
protected void handleOptions(Request request,Response response) throws IOException
{
if (!HttpMethod.OPTIONS.is(request.getMethod()))
response.sendError(HttpStatus.BAD_REQUEST_400);
request.setHandled(true);
response.setStatus(200);
response.setContentLength(0);
response.closeOutput();
}
/* ------------------------------------------------------------ */

View File

@ -446,7 +446,9 @@ public class ResourceHandler extends HandlerWrapper
// handle directories
if (resource.isDirectory())
{
if (!request.getPathInfo().endsWith(URIUtil.SLASH))
String pathInfo = request.getPathInfo();
boolean endsWithSlash=(pathInfo==null?request.getServletPath():pathInfo).endsWith(URIUtil.SLASH);
if (!endsWithSlash)
{
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)));
return;

View File

@ -135,6 +135,45 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
}
@Test
public void testOPTIONS() throws Exception
{
configureServer(new OptionsHandler());
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
os.write(("OPTIONS * HTTP/1.1\r\n"
+ "Host: "+_serverURI.getHost()+"\r\n"
+ "Connection: close\r\n"
+ "\r\n").getBytes(StandardCharsets.ISO_8859_1));
os.flush();
// Read the response.
String response = readResponse(client);
Assert.assertThat(response, Matchers.containsString("HTTP/1.1 200 OK"));
Assert.assertThat(response, Matchers.containsString("Allow: GET"));
}
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
os.write(("GET * HTTP/1.1\r\n"
+ "Host: "+_serverURI.getHost()+"\r\n"
+ "Connection: close\r\n"
+ "\r\n").getBytes(StandardCharsets.ISO_8859_1));
os.flush();
// Read the response.
String response = readResponse(client);
Assert.assertThat(response, Matchers.containsString("HTTP/1.1 400 "));
Assert.assertThat(response, Matchers.not(Matchers.containsString("Allow: ")));
}
}
/*
* Feed a full header method

View File

@ -150,6 +150,21 @@ public class HttpServerTestFixture
}
}
protected static class OptionsHandler extends AbstractHandler
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
if (request.getMethod().equals("OPTIONS"))
response.setStatus(200);
else
response.setStatus(500);
response.setHeader("Allow", "GET");
}
}
protected static class HelloWorldHandler extends AbstractHandler
{
@Override

View File

@ -589,6 +589,11 @@ public class ServletHandler extends ScopedHandler
}
catch(RuntimeIOException e)
{
if (e.getCause() instanceof IOException)
{
LOG.debug(e);
throw (IOException)e.getCause();
}
throw e;
}
catch(Exception e)

View File

@ -719,6 +719,10 @@ public class DoSFilter implements Filter
prefix -= 8;
++index;
}
if (index == result.length)
return result;
// Sets the _prefix_ most significant bits to 1
result[index] = (byte)~((1 << (8 - prefix)) - 1);
return result;
@ -1045,6 +1049,18 @@ public class DoSFilter implements Filter
_whitelist.addAll(result);
LOG.debug("Whitelisted IP addresses: {}", result);
}
/**
* Set a list of IP addresses that will not be rate limited.
*
* @param values whitelist
*/
public void setWhitelist(List<String> values)
{
clearWhitelist();
_whitelist.addAll(values);
LOG.debug("Whitelisted IP addresses: {}", values);
}
/**
* Clears the list of whitelisted IP addresses

View File

@ -79,19 +79,20 @@ public class DoSFilterTest extends AbstractDoSFilterTest
{
DoSFilter filter = new DoSFilter();
List<String> whitelist = new ArrayList<String>();
whitelist.add("192.168.0.1");
whitelist.add("192.168.0.1/32");
whitelist.add("10.0.0.0/8");
whitelist.add("4d8:0:a:1234:ABc:1F:b18:17");
whitelist.add("4d8:0:a:1234:ABc:1F:0:0/96");
Assert.assertTrue(filter.checkWhitelist(whitelist, "192.168.0.1"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.0.0.0"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "0.0.0.0"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:17"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:0"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1D:0:0"));
filter.setWhitelist(whitelist);
Assert.assertTrue(filter.checkWhitelist("192.168.0.1"));
Assert.assertFalse(filter.checkWhitelist("192.168.0.2"));
Assert.assertFalse(filter.checkWhitelist("11.12.13.14"));
Assert.assertTrue(filter.checkWhitelist("10.11.12.13"));
Assert.assertTrue(filter.checkWhitelist("10.0.0.0"));
Assert.assertFalse(filter.checkWhitelist("0.0.0.0"));
Assert.assertTrue(filter.checkWhitelist("4d8:0:a:1234:ABc:1F:b18:17"));
Assert.assertTrue(filter.checkWhitelist("4d8:0:a:1234:ABc:1F:b18:0"));
Assert.assertFalse(filter.checkWhitelist("4d8:0:a:1234:ABc:1D:0:0"));
}
private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws InterruptedException

View File

@ -193,7 +193,7 @@ public abstract class Resource implements ResourceFactory, Closeable
}
}
return newResource(url);
return newResource(url, useCaches);
}
/* ------------------------------------------------------------ */

View File

@ -303,7 +303,7 @@ public class URLResource extends Resource
path = URIUtil.canonicalPath(path);
return newResource(URIUtil.addPaths(_url.toExternalForm(),path));
return newResource(URIUtil.addPaths(_url.toExternalForm(),path), _useCaches);
}
/* ------------------------------------------------------------ */

View File

@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Properties;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.xml.XmlConfiguration;
@ -119,7 +120,7 @@ public class TestableJettyServer
for (int i = 0; i < this._xmlConfigurations.size(); i++)
{
URL configURL = this._xmlConfigurations.get(i);
// System.err.println("configuring: "+configURL);
System.err.println("configuring: "+configURL);
XmlConfiguration configuration = new XmlConfiguration(configURL);
if (last != null)
{
@ -177,7 +178,6 @@ public class TestableJettyServer
// Find the active server port.
this._serverPort = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort();
// System.err.println("Server Port="+_serverPort);
Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + _serverPort + ">",(1 <= this._serverPort) && (this._serverPort <= 65535));
}

View File

@ -1,21 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Set connectors -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.bio.SocketConnector">
<Set name="host"><SystemProperty name="jetty.http.host" /></Set>
<Set name="idleTimeout">300000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -1,28 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Set connectors -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ssl.SslSocketConnector">
<Set name="host"><SystemProperty name="jetty.http.host" /></Set>
<Set name="idleTimeout">300000</Set>
<Set name="Acceptors">2</Set>
<Set name="statsOn">false</Set>
<Set name="keystore"><Property name="test.resourcesdir" default="src/test/resources" />/keystore</Set>
<Set name="password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="keyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
<!--
<Set name="truststore"><Property name="test.resourcesdir" default="src/test/resources" />/keystore</Set>
<Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
-->
</New>
</Arg>
</Call>
</Configure>