Merge remote-tracking branch 'origin/jetty-8'
Conflicts: jetty-client/src/main/java/org/eclipse/jetty/client/AsyncHttpConnection.java jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java jetty-server/src/main/java/org/eclipse/jetty/server/Server.java jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java test-jetty-webapp/src/main/java/com/acme/CookieDump.java test-jetty-webapp/src/main/java/com/acme/HelloWorld.java
This commit is contained in:
commit
346918577f
|
@ -29,7 +29,6 @@ import java.util.List;
|
||||||
import org.apache.tools.ant.BuildException;
|
import org.apache.tools.ant.BuildException;
|
||||||
import org.eclipse.jetty.ant.types.Connector;
|
import org.eclipse.jetty.ant.types.Connector;
|
||||||
import org.eclipse.jetty.ant.types.ContextHandlers;
|
import org.eclipse.jetty.ant.types.ContextHandlers;
|
||||||
import org.eclipse.jetty.ant.utils.Monitor;
|
|
||||||
import org.eclipse.jetty.ant.utils.ServerProxy;
|
import org.eclipse.jetty.ant.utils.ServerProxy;
|
||||||
import org.eclipse.jetty.ant.utils.TaskLog;
|
import org.eclipse.jetty.ant.utils.TaskLog;
|
||||||
import org.eclipse.jetty.security.LoginService;
|
import org.eclipse.jetty.security.LoginService;
|
||||||
|
@ -37,6 +36,7 @@ import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.RequestLog;
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
|
@ -95,7 +95,6 @@ public class ServerProxyImpl implements ServerProxy
|
||||||
/** wait for all jetty threads to exit or continue */
|
/** wait for all jetty threads to exit or continue */
|
||||||
private boolean daemon;
|
private boolean daemon;
|
||||||
|
|
||||||
private Monitor monitor;
|
|
||||||
|
|
||||||
private boolean configured = false;
|
private boolean configured = false;
|
||||||
|
|
||||||
|
@ -267,8 +266,6 @@ public class ServerProxyImpl implements ServerProxy
|
||||||
System.setProperty("jetty.ant.server.host", host);
|
System.setProperty("jetty.ant.server.host", host);
|
||||||
}
|
}
|
||||||
|
|
||||||
startMonitor();
|
|
||||||
|
|
||||||
startScanners();
|
startScanners();
|
||||||
|
|
||||||
TaskLog.log("Jetty AntTask Started");
|
TaskLog.log("Jetty AntTask Started");
|
||||||
|
@ -356,6 +353,11 @@ public class ServerProxyImpl implements ServerProxy
|
||||||
|
|
||||||
configured = true;
|
configured = true;
|
||||||
|
|
||||||
|
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||||
|
monitor.setPort(stopPort);
|
||||||
|
monitor.setKey(stopKey);
|
||||||
|
monitor.setExitVm(false);
|
||||||
|
|
||||||
if (tempDirectory != null && !tempDirectory.exists())
|
if (tempDirectory != null && !tempDirectory.exists())
|
||||||
tempDirectory.mkdirs();
|
tempDirectory.mkdirs();
|
||||||
|
|
||||||
|
@ -430,17 +432,7 @@ public class ServerProxyImpl implements ServerProxy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private void startMonitor() throws Exception
|
|
||||||
{
|
|
||||||
if (stopPort > 0 && stopKey != null && monitor == null)
|
|
||||||
{
|
|
||||||
monitor = new Monitor(stopPort, stopKey, new Server[] {server});
|
|
||||||
monitor.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// 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.ant.utils;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitor
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Monitor extends Thread
|
|
||||||
{
|
|
||||||
private String stopKey;
|
|
||||||
|
|
||||||
private Server[] servers;
|
|
||||||
|
|
||||||
private ServerSocket serverSocket;
|
|
||||||
|
|
||||||
public Monitor(int port, String key, Server[] servers)
|
|
||||||
throws Exception
|
|
||||||
{
|
|
||||||
if (port <= 0) throw new IllegalStateException("Bad stop port");
|
|
||||||
if (key == null) throw new IllegalStateException("Bad stop key");
|
|
||||||
if (servers == null) throw new IllegalStateException("No servers");
|
|
||||||
|
|
||||||
this.stopKey = key;
|
|
||||||
this.servers = servers;
|
|
||||||
setName("JettyStopTaskMonitor");
|
|
||||||
setDaemon(true);
|
|
||||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
|
||||||
serverSocket = new ServerSocket();
|
|
||||||
serverSocket.setReuseAddress(true);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
serverSocket.bind(address, 1);
|
|
||||||
TaskLog.log("Jetty monitoring port 127.0.0.1:" + port);
|
|
||||||
}
|
|
||||||
catch (IOException x)
|
|
||||||
{
|
|
||||||
TaskLog.log("Error binding to stop port 127.0.0.1:" + port);
|
|
||||||
throw x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.lang.Thread#run()
|
|
||||||
*/
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
while (serverSocket != null)
|
|
||||||
{
|
|
||||||
Socket socket = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket = serverSocket.accept();
|
|
||||||
socket.setSoLinger(false, 0);
|
|
||||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
|
|
||||||
String key = lin.readLine();
|
|
||||||
System.err.println("Monitor: " + key);
|
|
||||||
if (!stopKey.equals(key)) continue;
|
|
||||||
String cmd = lin.readLine();
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
close(serverSocket);
|
|
||||||
serverSocket = null;
|
|
||||||
for (Server s : servers)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
TaskLog.log("Stopping server: " + s);
|
|
||||||
s.stop();
|
|
||||||
TaskLog.log("Stopped server: " + s);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TaskLog.log(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// confirm the stop
|
|
||||||
socket.getOutputStream().write("Stopped\r\n".getBytes());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
TaskLog.log("Unsupported monitor operation: " + cmd);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TaskLog.log(e.getMessage());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
close(socket);
|
|
||||||
socket = null;
|
|
||||||
close(serverSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param c
|
|
||||||
*/
|
|
||||||
private void close(Closeable c)
|
|
||||||
{
|
|
||||||
if (c == null) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
TaskLog.log(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,6 +42,7 @@ import org.eclipse.jetty.security.LoginService;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.RequestLog;
|
import org.eclipse.jetty.server.RequestLog;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||||
|
@ -470,6 +471,14 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
{
|
{
|
||||||
getLog().debug("Starting Jetty Server ...");
|
getLog().debug("Starting Jetty Server ...");
|
||||||
|
|
||||||
|
if(stopPort>0 && stopKey!=null)
|
||||||
|
{
|
||||||
|
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||||
|
monitor.setPort(stopPort);
|
||||||
|
monitor.setKey(stopKey);
|
||||||
|
monitor.setExitVm(!daemon);
|
||||||
|
}
|
||||||
|
|
||||||
printSystemProperties();
|
printSystemProperties();
|
||||||
|
|
||||||
//apply any config from a jetty.xml file first which is able to
|
//apply any config from a jetty.xml file first which is able to
|
||||||
|
@ -530,11 +539,6 @@ public abstract class AbstractJettyMojo extends AbstractMojo
|
||||||
|
|
||||||
getLog().info("Started Jetty Server");
|
getLog().info("Started Jetty Server");
|
||||||
|
|
||||||
if(stopPort>0 && stopKey!=null)
|
|
||||||
{
|
|
||||||
Monitor monitor = new Monitor(stopPort, stopKey, new Server[]{server}, !daemon);
|
|
||||||
monitor.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the scanner thread (if necessary) on the main webapp
|
// start the scanner thread (if necessary) on the main webapp
|
||||||
configureScanner ();
|
configureScanner ();
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// 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.maven.plugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitor
|
|
||||||
*
|
|
||||||
* Listens for stop commands eg via mvn jetty:stop and
|
|
||||||
* causes jetty to stop either by exiting the jvm, or
|
|
||||||
* by stopping the Server instances. The choice of
|
|
||||||
* behaviour is controlled by either passing true
|
|
||||||
* (exit jvm) or false (stop Servers) in the constructor.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Monitor extends Thread
|
|
||||||
{
|
|
||||||
private String _key;
|
|
||||||
private Server[] _servers;
|
|
||||||
|
|
||||||
ServerSocket _serverSocket;
|
|
||||||
boolean _kill;
|
|
||||||
|
|
||||||
public Monitor(int port, String key, Server[] servers, boolean kill)
|
|
||||||
throws UnknownHostException, IOException
|
|
||||||
{
|
|
||||||
if (port <= 0)
|
|
||||||
throw new IllegalStateException ("Bad stop port");
|
|
||||||
if (key==null)
|
|
||||||
throw new IllegalStateException("Bad stop key");
|
|
||||||
|
|
||||||
_key = key;
|
|
||||||
_servers = servers;
|
|
||||||
_kill = kill;
|
|
||||||
setDaemon(true);
|
|
||||||
setName("StopJettyPluginMonitor");
|
|
||||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
|
||||||
_serverSocket=new ServerSocket();
|
|
||||||
_serverSocket.setReuseAddress(true);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_serverSocket.bind(address,1);
|
|
||||||
}
|
|
||||||
catch (IOException x)
|
|
||||||
{
|
|
||||||
System.out.println("Error binding to stop port 127.0.0.1:"+port);
|
|
||||||
throw x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
while (_serverSocket != null)
|
|
||||||
{
|
|
||||||
Socket socket = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket = _serverSocket.accept();
|
|
||||||
socket.setSoLinger(false, 0);
|
|
||||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
|
|
||||||
String key = lin.readLine();
|
|
||||||
if (!_key.equals(key)) continue;
|
|
||||||
String cmd = lin.readLine();
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
|
||||||
try{socket.close();}catch (Exception e){e.printStackTrace();}
|
|
||||||
try{_serverSocket.close();}catch (Exception e){e.printStackTrace();}
|
|
||||||
|
|
||||||
_serverSocket = null;
|
|
||||||
|
|
||||||
if (_kill)
|
|
||||||
{
|
|
||||||
System.out.println("Killing Jetty");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i=0; _servers != null && i < _servers.length; i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
System.out.println("Stopping server "+i);
|
|
||||||
_servers[i].stop();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
System.out.println("Unsupported monitor operation");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (socket != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ import java.util.TreeMap;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||||
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;
|
||||||
|
@ -57,7 +58,7 @@ public class Starter
|
||||||
|
|
||||||
private JettyServer server;
|
private JettyServer server;
|
||||||
private JettyWebAppContext webApp;
|
private JettyWebAppContext webApp;
|
||||||
private Monitor monitor;
|
|
||||||
|
|
||||||
private int stopPort=0;
|
private int stopPort=0;
|
||||||
private String stopKey=null;
|
private String stopKey=null;
|
||||||
|
@ -172,7 +173,10 @@ public class Starter
|
||||||
System.err.println("STOP PORT="+stopPort+", STOP KEY="+stopKey);
|
System.err.println("STOP PORT="+stopPort+", STOP KEY="+stopKey);
|
||||||
if(stopPort>0 && stopKey!=null)
|
if(stopPort>0 && stopKey!=null)
|
||||||
{
|
{
|
||||||
monitor = new Monitor(stopPort, stopKey, new Server[]{server}, true);
|
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||||
|
monitor.setPort(stopPort);
|
||||||
|
monitor.setKey(stopKey);
|
||||||
|
monitor.setExitVm(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,9 +379,6 @@ public class Starter
|
||||||
*/
|
*/
|
||||||
public void run() throws Exception
|
public void run() throws Exception
|
||||||
{
|
{
|
||||||
if (monitor != null)
|
|
||||||
monitor.start();
|
|
||||||
|
|
||||||
LOG.info("Started Jetty Server");
|
LOG.info("Started Jetty Server");
|
||||||
server.start();
|
server.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// 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.runner;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Monitor
|
|
||||||
*
|
|
||||||
* Listens for stop commands eg via mvn jetty:stop and
|
|
||||||
* causes jetty to stop by exiting the virtual machine
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Monitor extends Thread
|
|
||||||
{
|
|
||||||
private String _key;
|
|
||||||
|
|
||||||
private ServerSocket _serverSocket;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public Monitor(int port, String key)
|
|
||||||
throws UnknownHostException, IOException
|
|
||||||
{
|
|
||||||
if (port <= 0)
|
|
||||||
throw new IllegalStateException ("Bad stop port");
|
|
||||||
if (key==null)
|
|
||||||
throw new IllegalStateException("Bad stop key");
|
|
||||||
|
|
||||||
_key = key;
|
|
||||||
|
|
||||||
setDaemon(true);
|
|
||||||
setName("JettyRunnerMonitor");
|
|
||||||
|
|
||||||
_serverSocket=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
|
||||||
_serverSocket.setReuseAddress(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
while (_serverSocket != null)
|
|
||||||
{
|
|
||||||
Socket socket = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket = _serverSocket.accept();
|
|
||||||
socket.setSoLinger(false, 0);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
|
|
||||||
String key = reader.readLine();
|
|
||||||
if (!_key.equals(key)) continue;
|
|
||||||
String cmd = reader.readLine();
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
closeSocket(socket);
|
|
||||||
closeServerSocket(_serverSocket);
|
|
||||||
|
|
||||||
System.err.println("Stopping Jetty");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
System.err.println("Unsupported monitor operation: "+cmd);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
closeSocket(socket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private void closeSocket(Socket socket)
|
|
||||||
{
|
|
||||||
if (socket != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private void closeServerSocket(ServerSocket socket)
|
|
||||||
{
|
|
||||||
if (socket != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.NCSARequestLog;
|
import org.eclipse.jetty.server.NCSARequestLog;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.server.ShutdownMonitor;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
|
@ -84,7 +85,6 @@ public class Runner
|
||||||
public static final int __defaultPort = 8080;
|
public static final int __defaultPort = 8080;
|
||||||
|
|
||||||
protected Server _server;
|
protected Server _server;
|
||||||
protected Monitor _monitor;
|
|
||||||
protected URLClassLoader _classLoader;
|
protected URLClassLoader _classLoader;
|
||||||
protected Classpath _classpath = new Classpath();
|
protected Classpath _classpath = new Classpath();
|
||||||
protected ContextHandlerCollection _contexts;
|
protected ContextHandlerCollection _contexts;
|
||||||
|
@ -461,7 +461,10 @@ public class Runner
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
_monitor = new Monitor(stopPort, stopKey);
|
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
|
||||||
|
monitor.setPort(stopPort);
|
||||||
|
monitor.setKey(stopKey);
|
||||||
|
monitor.setExitVm(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,11 +501,6 @@ public class Runner
|
||||||
*/
|
*/
|
||||||
public void run() throws Exception
|
public void run() throws Exception
|
||||||
{
|
{
|
||||||
if (_monitor != null)
|
|
||||||
{
|
|
||||||
_monitor.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
_server.start();
|
_server.start();
|
||||||
_server.join();
|
_server.join();
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,7 +403,10 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
|
||||||
String info = URIUtil.canonicalPath(path);
|
String info = URIUtil.canonicalPath(path);
|
||||||
|
|
||||||
if (info == null)
|
if (info == null)
|
||||||
|
{
|
||||||
info = "/";
|
info = "/";
|
||||||
|
_request.setRequestURI("");
|
||||||
|
}
|
||||||
_request.setPathInfo(info);
|
_request.setPathInfo(info);
|
||||||
_version = version == null ? HttpVersion.HTTP_0_9 : version;
|
_version = version == null ? HttpVersion.HTTP_0_9 : version;
|
||||||
_request.setHttpVersion(_version);
|
_request.setHttpVersion(_version);
|
||||||
|
|
|
@ -270,8 +270,10 @@ public class Server extends HandlerWrapper implements Attributes
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (getStopAtShutdown())
|
if (getStopAtShutdown()) {
|
||||||
ShutdownThread.register(this);
|
ShutdownThread.register(this);
|
||||||
|
ShutdownMonitor.getInstance().start(); // initialize
|
||||||
|
}
|
||||||
|
|
||||||
LOG.info("jetty-"+getVersion());
|
LOG.info("jetty-"+getVersion());
|
||||||
HttpGenerator.setServerVersion(getVersion());
|
HttpGenerator.setServerVersion(getVersion());
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.LineNumberReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown/Stop Monitor thread.
|
||||||
|
* <p>
|
||||||
|
* This thread listens on the port specified by the STOP.PORT system parameter (defaults to -1 for not listening) for request authenticated with the key given
|
||||||
|
* by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
|
||||||
|
* <p>
|
||||||
|
* If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout.
|
||||||
|
* <p>
|
||||||
|
* Commands "stop" and "status" are currently supported.
|
||||||
|
*/
|
||||||
|
public class ShutdownMonitor extends Thread
|
||||||
|
{
|
||||||
|
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
||||||
|
static class Holder
|
||||||
|
{
|
||||||
|
static ShutdownMonitor instance = new ShutdownMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShutdownMonitor getInstance()
|
||||||
|
{
|
||||||
|
return Holder.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean DEBUG;
|
||||||
|
private int port;
|
||||||
|
private String key;
|
||||||
|
private boolean exitVm;
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a ShutdownMonitor using configuration from the System properties.
|
||||||
|
* <p>
|
||||||
|
* <code>STOP.PORT</code> = the port to listen on (empty, null, or values less than 0 disable the stop ability)<br>
|
||||||
|
* <code>STOP.KEY</code> = the magic key/passphrase to allow the stop (defaults to "eclipse")<br>
|
||||||
|
* <p>
|
||||||
|
* Note: server socket will only listen on localhost, and a successful stop will issue a System.exit() call.
|
||||||
|
*/
|
||||||
|
private ShutdownMonitor()
|
||||||
|
{
|
||||||
|
Properties props = System.getProperties();
|
||||||
|
|
||||||
|
this.DEBUG = props.containsKey("DEBUG");
|
||||||
|
|
||||||
|
// Use values passed thru via /jetty-start/
|
||||||
|
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
||||||
|
this.key = props.getProperty("STOP.KEY","eclipse");
|
||||||
|
this.exitVm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(ServerSocket server)
|
||||||
|
{
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server.close();
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(Socket socket)
|
||||||
|
{
|
||||||
|
if (socket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void debug(String format, Object... args)
|
||||||
|
{
|
||||||
|
if (DEBUG)
|
||||||
|
{
|
||||||
|
System.err.printf("[ShutdownMonitor] " + format + "%n",args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void debug(Throwable t)
|
||||||
|
{
|
||||||
|
if (DEBUG)
|
||||||
|
{
|
||||||
|
t.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey()
|
||||||
|
{
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort()
|
||||||
|
{
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerSocket getServerSocket()
|
||||||
|
{
|
||||||
|
return serverSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExitVm()
|
||||||
|
{
|
||||||
|
return exitVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Socket socket = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket = serverSocket.accept();
|
||||||
|
|
||||||
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String key = lin.readLine();
|
||||||
|
if (!this.key.equals(key))
|
||||||
|
{
|
||||||
|
System.err.println("Ignoring command with incorrect key");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
|
||||||
|
String cmd = lin.readLine();
|
||||||
|
debug("command=%s",cmd);
|
||||||
|
if ("stop".equals(cmd))
|
||||||
|
{
|
||||||
|
// Graceful Shutdown
|
||||||
|
debug("Issuing graceful shutdown..");
|
||||||
|
ShutdownThread.getInstance().run();
|
||||||
|
|
||||||
|
// Reply to client
|
||||||
|
debug("Informing client that we are stopped.");
|
||||||
|
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// Shutdown Monitor
|
||||||
|
debug("Shutting down monitor");
|
||||||
|
close(socket);
|
||||||
|
close(serverSocket);
|
||||||
|
|
||||||
|
if (exitVm)
|
||||||
|
{
|
||||||
|
// Kill JVM
|
||||||
|
debug("Killing JVM");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ("status".equals(cmd))
|
||||||
|
{
|
||||||
|
// Reply to client
|
||||||
|
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println(e.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
close(socket);
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDebug(boolean flag)
|
||||||
|
{
|
||||||
|
this.DEBUG = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExitVm(boolean exitVm)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
|
}
|
||||||
|
this.exitVm = exitVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(String key)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
|
}
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
|
}
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
System.out.printf("ShutdownMonitor already started");
|
||||||
|
return; // cannot start it again
|
||||||
|
}
|
||||||
|
startListenSocket();
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListenSocket()
|
||||||
|
{
|
||||||
|
if (this.port < 0)
|
||||||
|
{
|
||||||
|
System.out.println("ShutdownMonitor not in use (port < 0): " + port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
setDaemon(true);
|
||||||
|
setName("ShutdownMonitor");
|
||||||
|
|
||||||
|
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
|
||||||
|
if (this.port == 0)
|
||||||
|
{
|
||||||
|
// server assigned port in use
|
||||||
|
this.port = serverSocket.getLocalPort();
|
||||||
|
System.out.printf("STOP.PORT=%d%n",this.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.key == null)
|
||||||
|
{
|
||||||
|
// create random key
|
||||||
|
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
||||||
|
System.out.printf("STOP.KEY=%s%n",this.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// establish the port and key that are in use
|
||||||
|
debug("STOP.PORT=%d",this.port);
|
||||||
|
debug("STOP.KEY=%s",this.key);
|
||||||
|
debug("%s",serverSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("%s[port=%d]",this.getClass().getName(),port);
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
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.StdErrLog;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -935,6 +936,7 @@ public class RequestTest
|
||||||
@Test
|
@Test
|
||||||
public void testHashDOS() throws Exception
|
public void testHashDOS() throws Exception
|
||||||
{
|
{
|
||||||
|
((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
|
||||||
LOG.info("Expecting maxFormKeys limit and Closing HttpParser exceptions...");
|
LOG.info("Expecting maxFormKeys limit and Closing HttpParser exceptions...");
|
||||||
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize",-1);
|
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormContentSize",-1);
|
||||||
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormKeys",1000);
|
_server.setAttribute("org.eclipse.jetty.server.Request.maxFormKeys",1000);
|
||||||
|
@ -979,11 +981,18 @@ public class RequestTest
|
||||||
"\r\n"+
|
"\r\n"+
|
||||||
buf;
|
buf;
|
||||||
|
|
||||||
long start=System.currentTimeMillis();
|
try
|
||||||
String response = _connector.getResponses(request);
|
{
|
||||||
assertTrue(response.contains("200 OK"));
|
long start=System.currentTimeMillis();
|
||||||
long now=System.currentTimeMillis();
|
String response = _connector.getResponses(request);
|
||||||
assertTrue((now-start)<5000);
|
assertTrue(response.contains("Form too many keys"));
|
||||||
|
long now=System.currentTimeMillis();
|
||||||
|
assertTrue((now-start)<5000);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,9 @@ import org.eclipse.jetty.util.LazyList;
|
||||||
import org.eclipse.jetty.util.MultiMap;
|
import org.eclipse.jetty.util.MultiMap;
|
||||||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
|
@ -77,6 +80,7 @@ import org.eclipse.jetty.util.StringUtil;
|
||||||
*/
|
*/
|
||||||
public class MultiPartFilter implements Filter
|
public class MultiPartFilter implements Filter
|
||||||
{
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(MultiPartFilter.class);
|
||||||
public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
|
public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
|
||||||
private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
|
private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
|
||||||
private File tempdir;
|
private File tempdir;
|
||||||
|
@ -275,11 +279,13 @@ public class MultiPartFilter implements Filter
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String[]> getParameterMap()
|
public Map<String, String[]> getParameterMap()
|
||||||
{
|
{
|
||||||
Map<String, String[]> cmap = new HashMap<>();
|
Map<String, String[]> cmap = new HashMap<String,String[]>();
|
||||||
|
|
||||||
for ( String key : _params.keySet() )
|
for ( Object key : _params.keySet() )
|
||||||
{
|
{
|
||||||
cmap.put(key,getParameterValues(key));
|
String[] a = LazyList.toStringArray(getParameter((String)key));
|
||||||
|
cmap.put((String)key,a);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableMap(cmap);
|
return Collections.unmodifiableMap(cmap);
|
||||||
|
|
|
@ -18,10 +18,23 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.servlets;
|
package org.eclipse.jetty.servlets;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
|
@ -194,6 +207,104 @@ public class MultipartFilterTest
|
||||||
assertTrue(response.getContent().indexOf("brown cow")>=0);
|
assertTrue(response.getContent().indexOf("brown cow")>=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBadlyEncodedFilename() throws Exception
|
||||||
|
{
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
// test GET
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
|
||||||
|
|
||||||
|
String content = "--" + boundary + "\r\n"+
|
||||||
|
"Content-Disposition: form-data; name=\"fileup\"; filename=\"Taken on Aug 22 \\ 2012.jpg\"\r\n"+
|
||||||
|
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||||
|
"How now brown cow."+
|
||||||
|
"\r\n--" + boundary + "--\r\n\r\n";
|
||||||
|
|
||||||
|
request.setContent(content);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
|
||||||
|
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||||
|
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
assertThat(response.getContent(), containsString("Filename [Taken on Aug 22 \\ 2012.jpg]"));
|
||||||
|
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBadlyEncodedMSFilename() throws Exception
|
||||||
|
{
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
// test GET
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
|
||||||
|
|
||||||
|
String content = "--" + boundary + "\r\n"+
|
||||||
|
"Content-Disposition: form-data; name=\"fileup\"; filename=\"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt\"\r\n"+
|
||||||
|
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||||
|
"How now brown cow."+
|
||||||
|
"\r\n--" + boundary + "--\r\n\r\n";
|
||||||
|
|
||||||
|
request.setContent(content);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
|
||||||
|
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||||
|
|
||||||
|
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
assertThat(response.getContent(), containsString("Filename [c:\\this\\really\\is\\some\\path\\to\\a\\file.txt]"));
|
||||||
|
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCorrectlyEncodedMSFilename() throws Exception
|
||||||
|
{
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
// test GET
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
|
||||||
|
|
||||||
|
String content = "--" + boundary + "\r\n"+
|
||||||
|
"Content-Disposition: form-data; name=\"fileup\"; filename=\"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt\"\r\n"+
|
||||||
|
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||||
|
"How now brown cow."+
|
||||||
|
"\r\n--" + boundary + "--\r\n\r\n";
|
||||||
|
|
||||||
|
request.setContent(content);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
|
||||||
|
//System.out.printf("Content: [%s]%n", response.getContent());
|
||||||
|
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
assertThat(response.getContent(), containsString("Filename [c:\\this\\really\\is\\some\\path\\to\\a\\file.txt]"));
|
||||||
|
assertThat(response.getContent(), containsString("How now brown cow."));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test multipart with parts encoded in base64 (RFC1521 section 5)
|
* Test multipart with parts encoded in base64 (RFC1521 section 5)
|
||||||
*/
|
*/
|
||||||
|
@ -467,20 +578,85 @@ public class MultipartFilterTest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoBody()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||||
|
assertTrue(response.getReason().startsWith("Missing content"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWhitespaceBodyWithCRLF()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
String whitespace = " \n\n\n\r\n\r\n\r\n\r\n";
|
||||||
|
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
request.setContent(whitespace);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||||
|
assertTrue(response.getReason().startsWith("Missing initial"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWhitespaceBody()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
String whitespace = " ";
|
||||||
|
|
||||||
|
String boundary="XyXyXy";
|
||||||
|
// generated and parsed test
|
||||||
|
HttpTester.Request request = HttpTester.newRequest();
|
||||||
|
HttpTester.Response response;
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setVersion("HTTP/1.0");
|
||||||
|
request.setHeader("Host","tester");
|
||||||
|
request.setURI("/context/dump");
|
||||||
|
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||||
|
request.setContent(whitespace);
|
||||||
|
|
||||||
|
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||||
|
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
|
||||||
|
assertTrue(response.getReason().startsWith("Missing initial"));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* see the testParameterMap test
|
* see the testParameterMap test
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static class TestServletParameterMap extends DumpServlet
|
public static class TestServletParameterMap extends DumpServlet
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
assertEquals("How now brown cow.", req.getParameterMap().get("strupContent-Type:"));
|
String[] content = req.getParameterMap().get("\"strup\"Content-Type: application/octet-stream");
|
||||||
|
assertThat (content[0], containsString("How now brown cow."));
|
||||||
super.doPost(req, resp);
|
super.doPost(req, resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -535,8 +711,17 @@ public class MultipartFilterTest
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
resp.getWriter().println((IO.toString(new FileInputStream((File)req.getAttribute("fileup")))));
|
FileInputStream in = null;
|
||||||
}
|
try {
|
||||||
|
File file = (File)req.getAttribute("fileup");
|
||||||
|
in = new FileInputStream(file);
|
||||||
|
|
||||||
|
PrintWriter out = resp.getWriter();
|
||||||
|
out.printf("Filename [%s]\r\n", req.getParameter("fileup"));
|
||||||
|
out.println(IO.toString(in));
|
||||||
|
} finally {
|
||||||
|
IO.close(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,13 @@ import java.util.Set;
|
||||||
/*-------------------------------------------*/
|
/*-------------------------------------------*/
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It allows an application to be started with
|
* Main start class. This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It
|
||||||
* the command "java -jar start.jar".
|
* allows an application to be started with the command "java -jar start.jar".
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file obtained as a resource or file.
|
* The behaviour of Main is controlled by the parsing of the {@link Config} "org/eclipse/start/start.config" file
|
||||||
|
* obtained as a resource or file.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class Main
|
public class Main
|
||||||
|
@ -91,7 +92,7 @@ public class Main
|
||||||
Main main = new Main();
|
Main main = new Main();
|
||||||
List<String> arguments = main.expandCommandLine(args);
|
List<String> arguments = main.expandCommandLine(args);
|
||||||
List<String> xmls = main.processCommandLine(arguments);
|
List<String> xmls = main.processCommandLine(arguments);
|
||||||
if (xmls!=null)
|
if (xmls != null)
|
||||||
main.start(xmls);
|
main.start(xmls);
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
|
@ -143,7 +144,7 @@ public class Main
|
||||||
|
|
||||||
List<String> parseStartIniFiles()
|
List<String> parseStartIniFiles()
|
||||||
{
|
{
|
||||||
List<String> ini_args=new ArrayList<String>();
|
List<String> ini_args = new ArrayList<String>();
|
||||||
File start_ini = new File(_jettyHome,"start.ini");
|
File start_ini = new File(_jettyHome,"start.ini");
|
||||||
if (start_ini.exists())
|
if (start_ini.exists())
|
||||||
ini_args.addAll(loadStartIni(start_ini));
|
ini_args.addAll(loadStartIni(start_ini));
|
||||||
|
@ -170,7 +171,7 @@ public class Main
|
||||||
{
|
{
|
||||||
int port = Integer.parseInt(Config.getProperty("STOP.PORT","-1"));
|
int port = Integer.parseInt(Config.getProperty("STOP.PORT","-1"));
|
||||||
String key = Config.getProperty("STOP.KEY",null);
|
String key = Config.getProperty("STOP.KEY",null);
|
||||||
int timeout = Integer.parseInt(Config.getProperty("STOP.WAIT", "0"));
|
int timeout = Integer.parseInt(Config.getProperty("STOP.WAIT","0"));
|
||||||
stop(port,key,timeout);
|
stop(port,key,timeout);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +213,7 @@ public class Main
|
||||||
if (!startDir.exists() || !startDir.canWrite())
|
if (!startDir.exists() || !startDir.canWrite())
|
||||||
startDir = new File(".");
|
startDir = new File(".");
|
||||||
|
|
||||||
File startLog = new File(startDir, START_LOG_ROLLOVER_DATEFORMAT.format(new Date()));
|
File startLog = new File(startDir,START_LOG_ROLLOVER_DATEFORMAT.format(new Date()));
|
||||||
|
|
||||||
if (!startLog.exists() && !startLog.createNewFile())
|
if (!startLog.exists() && !startLog.createNewFile())
|
||||||
{
|
{
|
||||||
|
@ -232,7 +233,7 @@ public class Main
|
||||||
PrintStream logger = new PrintStream(new FileOutputStream(startLog,false));
|
PrintStream logger = new PrintStream(new FileOutputStream(startLog,false));
|
||||||
System.setOut(logger);
|
System.setOut(logger);
|
||||||
System.setErr(logger);
|
System.setErr(logger);
|
||||||
System.out.println("Establishing "+ START_LOG_FILENAME + " on " + new Date());
|
System.out.println("Establishing " + START_LOG_FILENAME + " on " + new Date());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,11 +473,6 @@ public class Main
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void start(List<String> xmls) throws IOException, InterruptedException
|
public void start(List<String> xmls) throws IOException, InterruptedException
|
||||||
{
|
{
|
||||||
// Setup Start / Stop Monitoring
|
|
||||||
int port = Integer.parseInt(Config.getProperty("STOP.PORT","-1"));
|
|
||||||
String key = Config.getProperty("STOP.KEY",null);
|
|
||||||
Monitor monitor = new Monitor(port,key);
|
|
||||||
|
|
||||||
// Load potential Config (start.config)
|
// Load potential Config (start.config)
|
||||||
List<String> configuredXmls = loadConfig(xmls);
|
List<String> configuredXmls = loadConfig(xmls);
|
||||||
|
|
||||||
|
@ -561,9 +557,8 @@ public class Main
|
||||||
copyInThread(process.getErrorStream(),System.err);
|
copyInThread(process.getErrorStream(),System.err);
|
||||||
copyInThread(process.getInputStream(),System.out);
|
copyInThread(process.getInputStream(),System.out);
|
||||||
copyInThread(System.in,process.getOutputStream());
|
copyInThread(System.in,process.getOutputStream());
|
||||||
monitor.setProcess(process);
|
|
||||||
process.waitFor();
|
process.waitFor();
|
||||||
|
System.exit(0); // exit JVM when child process ends.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,11 +663,18 @@ public class Main
|
||||||
cmd.addArg(x);
|
cmd.addArg(x);
|
||||||
}
|
}
|
||||||
cmd.addRawArg("-Djetty.home=" + _jettyHome);
|
cmd.addRawArg("-Djetty.home=" + _jettyHome);
|
||||||
|
|
||||||
|
// Special Stop/Shutdown properties
|
||||||
|
ensureSystemPropertySet("STOP.PORT");
|
||||||
|
ensureSystemPropertySet("STOP.KEY");
|
||||||
|
|
||||||
|
// System Properties
|
||||||
for (String p : _sysProps)
|
for (String p : _sysProps)
|
||||||
{
|
{
|
||||||
String v = System.getProperty(p);
|
String v = System.getProperty(p);
|
||||||
cmd.addEqualsArg("-D" + p,v);
|
cmd.addEqualsArg("-D" + p,v);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.addArg("-cp");
|
cmd.addArg("-cp");
|
||||||
cmd.addRawArg(classpath.toString());
|
cmd.addRawArg(classpath.toString());
|
||||||
cmd.addRawArg(_config.getMainClassname());
|
cmd.addRawArg(_config.getMainClassname());
|
||||||
|
@ -695,6 +697,34 @@ public class Main
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that the System Properties are set (if defined as a System property, or start.config property, or
|
||||||
|
* start.ini property)
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* the key to be sure of
|
||||||
|
*/
|
||||||
|
private void ensureSystemPropertySet(String key)
|
||||||
|
{
|
||||||
|
if (_sysProps.contains(key))
|
||||||
|
{
|
||||||
|
return; // done
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties props = Config.getProperties();
|
||||||
|
if (props.containsKey(key))
|
||||||
|
{
|
||||||
|
String val = props.getProperty(key,null);
|
||||||
|
if (val == null)
|
||||||
|
{
|
||||||
|
return; // no value to set
|
||||||
|
}
|
||||||
|
// setup system property
|
||||||
|
_sysProps.add(key);
|
||||||
|
System.setProperty(key,val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String findJavaBin()
|
private String findJavaBin()
|
||||||
{
|
{
|
||||||
File javaHome = new File(System.getProperty("java.home"));
|
File javaHome = new File(System.getProperty("java.home"));
|
||||||
|
@ -897,8 +927,8 @@ public class Main
|
||||||
/**
|
/**
|
||||||
* Load Configuration.
|
* Load Configuration.
|
||||||
*
|
*
|
||||||
* No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to execute the {@link Class} specified by
|
* No specific configuration is real until a {@link Config#getCombinedClasspath(java.util.Collection)} is used to
|
||||||
* {@link Config#getMainClassname()} is executed.
|
* execute the {@link Class} specified by {@link Config#getMainClassname()} is executed.
|
||||||
*
|
*
|
||||||
* @param xmls
|
* @param xmls
|
||||||
* the command line specified xml configuration options.
|
* the command line specified xml configuration options.
|
||||||
|
@ -976,11 +1006,10 @@ public class Main
|
||||||
*/
|
*/
|
||||||
public void stop(int port, String key)
|
public void stop(int port, String key)
|
||||||
{
|
{
|
||||||
stop (port,key, 0);
|
stop(port,key,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop(int port, String key, int timeout)
|
||||||
public void stop (int port, String key, int timeout)
|
|
||||||
{
|
{
|
||||||
int _port = port;
|
int _port = port;
|
||||||
String _key = key;
|
String _key = key;
|
||||||
|
@ -1000,7 +1029,7 @@ public class Main
|
||||||
|
|
||||||
Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port);
|
Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port);
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
s.setSoTimeout(timeout*1000);
|
s.setSoTimeout(timeout * 1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OutputStream out = s.getOutputStream();
|
OutputStream out = s.getOutputStream();
|
||||||
|
@ -1009,11 +1038,15 @@ public class Main
|
||||||
|
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
{
|
{
|
||||||
System.err.println("Waiting"+(timeout > 0 ? (" "+timeout+"sec") : "")+" for jetty to stop");
|
System.err.printf("Waiting %,d seconds for jetty to stop%n",timeout);
|
||||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
||||||
String response=lin.readLine();
|
String response;
|
||||||
if ("Stopped".equals(response))
|
while ((response = lin.readLine()) != null)
|
||||||
System.err.println("Stopped");
|
{
|
||||||
|
Config.debug("Received \"" + response + "\"");
|
||||||
|
if ("Stopped".equals(response))
|
||||||
|
System.err.println("Server reports itself as Stopped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// 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.start;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
/*-------------------------------------------*/
|
|
||||||
/** Monitor thread.
|
|
||||||
* This thread listens on the port specified by the STOP.PORT system parameter
|
|
||||||
* (defaults to -1 for not listening) for request authenticated with the key given by the STOP.KEY
|
|
||||||
* system parameter (defaults to "eclipse") for admin requests.
|
|
||||||
* <p>
|
|
||||||
* If the stop port is set to zero, then a random port is assigned and the port number
|
|
||||||
* is printed to stdout.
|
|
||||||
* <p>
|
|
||||||
* Commands "stop" and * "status" are currently supported.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Monitor extends Thread
|
|
||||||
{
|
|
||||||
private Process _process;
|
|
||||||
private final int _port;
|
|
||||||
private final String _key;
|
|
||||||
|
|
||||||
ServerSocket _socket;
|
|
||||||
|
|
||||||
public Monitor(int port,String key)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(port<0)
|
|
||||||
return;
|
|
||||||
setDaemon(true);
|
|
||||||
setName("StopMonitor");
|
|
||||||
_socket=new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
|
||||||
if (port==0)
|
|
||||||
{
|
|
||||||
port=_socket.getLocalPort();
|
|
||||||
System.out.println(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key==null)
|
|
||||||
{
|
|
||||||
key=Long.toString((long)(Long.MAX_VALUE*Math.random()+this.hashCode()+System.currentTimeMillis()),36);
|
|
||||||
System.out.println("STOP.KEY="+key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Config.debug(e);
|
|
||||||
System.err.println("Error binding monitor port "+port+": "+e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_port=port;
|
|
||||||
_key=key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_socket!=null)
|
|
||||||
this.start();
|
|
||||||
else
|
|
||||||
System.err.println("WARN: Not listening on monitor port: "+_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Process getProcess()
|
|
||||||
{
|
|
||||||
return _process;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProcess(Process process)
|
|
||||||
{
|
|
||||||
_process = process;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Socket socket=null;
|
|
||||||
try{
|
|
||||||
socket=_socket.accept();
|
|
||||||
|
|
||||||
LineNumberReader lin=
|
|
||||||
new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
String key=lin.readLine();
|
|
||||||
if (!_key.equals(key))
|
|
||||||
{
|
|
||||||
System.err.println("Ignoring command with incorrect key");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String cmd=lin.readLine();
|
|
||||||
Config.debug("command=" + cmd);
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
if (_process!=null)
|
|
||||||
{
|
|
||||||
//if we have a child process, wait for it to finish before we stop
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_process.destroy();
|
|
||||||
_process.waitFor();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
System.err.println("Interrupted waiting for child to terminate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
socket.getOutputStream().write("Stopped\r\n".getBytes());
|
|
||||||
try {socket.close();}catch(Exception e){e.printStackTrace();}
|
|
||||||
try {_socket.close();}catch(Exception e){e.printStackTrace();}
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
else if ("status".equals(cmd))
|
|
||||||
{
|
|
||||||
socket.getOutputStream().write("OK\r\n".getBytes());
|
|
||||||
socket.getOutputStream().flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Config.debug(e);
|
|
||||||
System.err.println(e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (socket!=null)
|
|
||||||
{
|
|
||||||
try{socket.close();}catch(Exception e){}
|
|
||||||
}
|
|
||||||
socket=null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -464,7 +464,7 @@ public class MultiPartInputStreamParser
|
||||||
|
|
||||||
String contentTypeBoundary = "";
|
String contentTypeBoundary = "";
|
||||||
if (_contentType.indexOf("boundary=") >= 0)
|
if (_contentType.indexOf("boundary=") >= 0)
|
||||||
contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary=")), true).trim());
|
contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary="))).trim());
|
||||||
|
|
||||||
String boundary="--"+contentTypeBoundary;
|
String boundary="--"+contentTypeBoundary;
|
||||||
byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
|
byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
|
||||||
|
@ -525,7 +525,7 @@ public class MultiPartInputStreamParser
|
||||||
throw new IOException("Missing content-disposition");
|
throw new IOException("Missing content-disposition");
|
||||||
}
|
}
|
||||||
|
|
||||||
QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";");
|
QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";", false, true);
|
||||||
String name=null;
|
String name=null;
|
||||||
String filename=null;
|
String filename=null;
|
||||||
while(tok.hasMoreTokens())
|
while(tok.hasMoreTokens())
|
||||||
|
@ -535,9 +535,9 @@ public class MultiPartInputStreamParser
|
||||||
if(t.startsWith("form-data"))
|
if(t.startsWith("form-data"))
|
||||||
form_data=true;
|
form_data=true;
|
||||||
else if(tl.startsWith("name="))
|
else if(tl.startsWith("name="))
|
||||||
name=value(t, true);
|
name=value(t);
|
||||||
else if(tl.startsWith("filename="))
|
else if(tl.startsWith("filename="))
|
||||||
filename=value(t, false);
|
filename=filenameValue(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check disposition
|
// Check disposition
|
||||||
|
@ -703,25 +703,43 @@ public class MultiPartInputStreamParser
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private String value(String nameEqualsValue, boolean splitAfterSpace)
|
private String value(String nameEqualsValue)
|
||||||
{
|
{
|
||||||
String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
|
int idx = nameEqualsValue.indexOf('=');
|
||||||
int i=value.indexOf(';');
|
String value = nameEqualsValue.substring(idx+1).trim();
|
||||||
if(i>0)
|
return QuotedStringTokenizer.unquoteOnly(value);
|
||||||
value=value.substring(0,i);
|
|
||||||
if(value.startsWith("\""))
|
|
||||||
{
|
|
||||||
value=value.substring(1,value.indexOf('"',1));
|
|
||||||
}
|
|
||||||
else if (splitAfterSpace)
|
|
||||||
{
|
|
||||||
i=value.indexOf(' ');
|
|
||||||
if(i>0)
|
|
||||||
value=value.substring(0,i);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
private String filenameValue(String nameEqualsValue)
|
||||||
|
{
|
||||||
|
int idx = nameEqualsValue.indexOf('=');
|
||||||
|
String value = nameEqualsValue.substring(idx+1).trim();
|
||||||
|
|
||||||
|
if (value.matches(".??[a-z,A-Z]\\:\\\\[^\\\\].*"))
|
||||||
|
{
|
||||||
|
//incorrectly escaped IE filenames that have the whole path
|
||||||
|
//we just strip any leading & trailing quotes and leave it as is
|
||||||
|
char first=value.charAt(0);
|
||||||
|
if (first=='"' || first=='\'')
|
||||||
|
value=value.substring(1);
|
||||||
|
char last=value.charAt(value.length()-1);
|
||||||
|
if (last=='"' || last=='\'')
|
||||||
|
value = value.substring(0,value.length()-1);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
//unquote the string, but allow any backslashes that don't
|
||||||
|
//form a valid escape sequence to remain as many browsers
|
||||||
|
//even on *nix systems will not escape a filename containing
|
||||||
|
//backslashes
|
||||||
|
return QuotedStringTokenizer.unquoteOnly(value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class Base64InputStream extends InputStream
|
private static class Base64InputStream extends InputStream
|
||||||
{
|
{
|
||||||
BufferedReader _in;
|
BufferedReader _in;
|
||||||
|
|
|
@ -409,12 +409,21 @@ public class QuotedStringTokenizer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public static String unquoteOnly(String s)
|
||||||
|
{
|
||||||
|
return unquoteOnly(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Unquote a string, NOT converting unicode sequences
|
/** Unquote a string, NOT converting unicode sequences
|
||||||
* @param s The string to unquote.
|
* @param s The string to unquote.
|
||||||
|
* @param lenient if true, will leave in backslashes that aren't valid escapes
|
||||||
* @return quoted string
|
* @return quoted string
|
||||||
*/
|
*/
|
||||||
public static String unquoteOnly(String s)
|
public static String unquoteOnly(String s, boolean lenient)
|
||||||
{
|
{
|
||||||
if (s==null)
|
if (s==null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -435,6 +444,10 @@ public class QuotedStringTokenizer
|
||||||
if (escape)
|
if (escape)
|
||||||
{
|
{
|
||||||
escape=false;
|
escape=false;
|
||||||
|
if (lenient && !isValidEscaping(c))
|
||||||
|
{
|
||||||
|
b.append('\\');
|
||||||
|
}
|
||||||
b.append(c);
|
b.append(c);
|
||||||
}
|
}
|
||||||
else if (c=='\\')
|
else if (c=='\\')
|
||||||
|
@ -450,12 +463,18 @@ public class QuotedStringTokenizer
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public static String unquote(String s)
|
||||||
|
{
|
||||||
|
return unquote(s,false);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Unquote a string.
|
/** Unquote a string.
|
||||||
* @param s The string to unquote.
|
* @param s The string to unquote.
|
||||||
* @return quoted string
|
* @return quoted string
|
||||||
*/
|
*/
|
||||||
public static String unquote(String s)
|
public static String unquote(String s, boolean lenient)
|
||||||
{
|
{
|
||||||
if (s==null)
|
if (s==null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -512,6 +531,10 @@ public class QuotedStringTokenizer
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (lenient && !isValidEscaping(c))
|
||||||
|
{
|
||||||
|
b.append('\\');
|
||||||
|
}
|
||||||
b.append(c);
|
b.append(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,6 +551,20 @@ public class QuotedStringTokenizer
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** Check that char c (which is preceded by a backslash) is a valid
|
||||||
|
* escape sequence.
|
||||||
|
* @param c
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean isValidEscaping(char c)
|
||||||
|
{
|
||||||
|
return ((c == 'n') || (c == 'r') || (c == 't') ||
|
||||||
|
(c == 'f') || (c == 'b') || (c == '\\') ||
|
||||||
|
(c == '/') || (c == '"') || (c == 'u'));
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* @return handle double quotes if true
|
* @return handle double quotes if true
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ReadLineInputStream extends BufferedInputStream
|
||||||
int m=markpos;
|
int m=markpos;
|
||||||
markpos=-1;
|
markpos=-1;
|
||||||
if (pos>m)
|
if (pos>m)
|
||||||
return new String(buf,m,pos-m, StringUtil.__UTF8_CHARSET);
|
return new String(buf,m,pos-m,StringUtil.__UTF8_CHARSET);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,10 +226,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
key = null;
|
key = null;
|
||||||
value=null;
|
value=null;
|
||||||
if (maxKeys>0 && map.size()>maxKeys)
|
if (maxKeys>0 && map.size()>maxKeys)
|
||||||
{
|
throw new IllegalStateException("Form too many keys");
|
||||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (key!=null)
|
if (key!=null)
|
||||||
|
@ -385,10 +382,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
key = null;
|
key = null;
|
||||||
value=null;
|
value=null;
|
||||||
if (maxKeys>0 && map.size()>maxKeys)
|
if (maxKeys>0 && map.size()>maxKeys)
|
||||||
{
|
throw new IllegalStateException("Form too many keys");
|
||||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
|
@ -471,10 +465,7 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
key = null;
|
key = null;
|
||||||
value=null;
|
value=null;
|
||||||
if (maxKeys>0 && map.size()>maxKeys)
|
if (maxKeys>0 && map.size()>maxKeys)
|
||||||
{
|
throw new IllegalStateException("Form too many keys");
|
||||||
LOG.warn("maxFormKeys limit exceeded keys>{}",maxKeys);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
|
@ -599,6 +590,8 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
|
||||||
}
|
}
|
||||||
key = null;
|
key = null;
|
||||||
value=null;
|
value=null;
|
||||||
|
if (maxKeys>0 && map.size()>maxKeys)
|
||||||
|
throw new IllegalStateException("Form too many keys");
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (key!=null)
|
if (key!=null)
|
||||||
|
|
|
@ -446,6 +446,71 @@ public class MultiPartInputStreamTest
|
||||||
assertThat(baos.toString("UTF-8"), is("Other"));
|
assertThat(baos.toString("UTF-8"), is("Other"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBadlyEncodedFilename() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
String contents = "--AaB03x\r\n"+
|
||||||
|
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"Taken on Aug 22 \\ 2012.jpg" + "\"\r\n"+
|
||||||
|
"Content-Type: text/plain\r\n"+
|
||||||
|
"\r\n"+"stuff"+
|
||||||
|
"aaa"+"\r\n" +
|
||||||
|
"--AaB03x--\r\n";
|
||||||
|
|
||||||
|
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||||
|
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||||
|
_contentType,
|
||||||
|
config,
|
||||||
|
_tmpDir);
|
||||||
|
mpis.setDeleteOnExit(true);
|
||||||
|
Collection<Part> parts = mpis.getParts();
|
||||||
|
assertThat(parts.size(), is(1));
|
||||||
|
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("Taken on Aug 22 \\ 2012.jpg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBadlyEncodedMSFilename() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
String contents = "--AaB03x\r\n"+
|
||||||
|
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\this\\really\\is\\some\\path\\to\\a\\file.txt" + "\"\r\n"+
|
||||||
|
"Content-Type: text/plain\r\n"+
|
||||||
|
"\r\n"+"stuff"+
|
||||||
|
"aaa"+"\r\n" +
|
||||||
|
"--AaB03x--\r\n";
|
||||||
|
|
||||||
|
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||||
|
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||||
|
_contentType,
|
||||||
|
config,
|
||||||
|
_tmpDir);
|
||||||
|
mpis.setDeleteOnExit(true);
|
||||||
|
Collection<Part> parts = mpis.getParts();
|
||||||
|
assertThat(parts.size(), is(1));
|
||||||
|
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCorrectlyEncodedMSFilename() throws Exception
|
||||||
|
{
|
||||||
|
String contents = "--AaB03x\r\n"+
|
||||||
|
"content-disposition: form-data; name=\"stuff\"; filename=\"" +"c:\\\\this\\\\really\\\\is\\\\some\\\\path\\\\to\\\\a\\\\file.txt" + "\"\r\n"+
|
||||||
|
"Content-Type: text/plain\r\n"+
|
||||||
|
"\r\n"+"stuff"+
|
||||||
|
"aaa"+"\r\n" +
|
||||||
|
"--AaB03x--\r\n";
|
||||||
|
|
||||||
|
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||||
|
MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(contents.getBytes()),
|
||||||
|
_contentType,
|
||||||
|
config,
|
||||||
|
_tmpDir);
|
||||||
|
mpis.setDeleteOnExit(true);
|
||||||
|
Collection<Part> parts = mpis.getParts();
|
||||||
|
assertThat(parts.size(), is(1));
|
||||||
|
assertThat(((MultiPartInputStreamParser.MultiPart)parts.iterator().next()).getContentDispositionFilename(), is("c:\\this\\really\\is\\some\\path\\to\\a\\file.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testMulti ()
|
public void testMulti ()
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
|
@ -458,6 +523,9 @@ public class MultiPartInputStreamTest
|
||||||
testMulti("stuff with spaces.txt");
|
testMulti("stuff with spaces.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void testMulti(String filename) throws IOException, ServletException
|
private void testMulti(String filename) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.util;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -190,4 +188,21 @@ public class QuotedStringTokenizerTest
|
||||||
assertEquals("ba\\uXXXXaaa", QuotedStringTokenizer.unquoteOnly("\"ba\\\\uXXXXaaa\""));
|
assertEquals("ba\\uXXXXaaa", QuotedStringTokenizer.unquoteOnly("\"ba\\\\uXXXXaaa\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When encountering a Content-Disposition line during a multi-part mime file
|
||||||
|
* upload, the filename="..." field can contain '\' characters that do not
|
||||||
|
* belong to a proper escaping sequence, this tests QuotedStringTokenizer to
|
||||||
|
* ensure that it preserves those slashes for where they cannot be escaped.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNextTokenOnContentDisposition()
|
||||||
|
{
|
||||||
|
String content_disposition = "form-data; name=\"fileup\"; filename=\"Taken on Aug 22 \\ 2012.jpg\"";
|
||||||
|
|
||||||
|
QuotedStringTokenizer tok=new QuotedStringTokenizer(content_disposition,";",false,true);
|
||||||
|
|
||||||
|
assertEquals("form-data", tok.nextToken().trim());
|
||||||
|
assertEquals("name=\"fileup\"", tok.nextToken().trim());
|
||||||
|
assertEquals("filename=\"Taken on Aug 22 \\ 2012.jpg\"", tok.nextToken().trim());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,16 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||||
import org.eclipse.jetty.server.handler.HandlerList;
|
import org.eclipse.jetty.server.handler.HandlerList;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
@ -183,6 +188,36 @@ public class WebAppContextTest
|
||||||
assertFalse(context.isProtectedTarget("/something-else/web-inf"));
|
assertFalse(context.isProtectedTarget("/something-else/web-inf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullPath() throws Exception
|
||||||
|
{
|
||||||
|
Server server = new Server(0);
|
||||||
|
HandlerList handlers = new HandlerList();
|
||||||
|
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||||
|
WebAppContext context = new WebAppContext();
|
||||||
|
context.setBaseResource(Resource.newResource("./src/test/webapp"));
|
||||||
|
context.setContextPath("/");
|
||||||
|
server.setHandler(handlers);
|
||||||
|
handlers.addHandler(contexts);
|
||||||
|
contexts.addHandler(context);
|
||||||
|
|
||||||
|
LocalConnector connector = new LocalConnector(server);
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String response = connector.getResponses("GET http://localhost:8080 HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n");
|
||||||
|
Assert.assertTrue(response.indexOf("200 OK")>=0);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ServletA extends GenericServlet
|
class ServletA extends GenericServlet
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,8 @@ package com.acme;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
|
@ -120,4 +122,21 @@ public class CookieDump extends HttpServlet
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
// For testing --stop with STOP.WAIT handling of the jetty-start behavior.
|
||||||
|
if (Boolean.getBoolean("test.slow.destroy"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TimeUnit.SECONDS.sleep(10);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue