propagate from branch 'i2p.i2p' (head 156f8e6137be3c25aa70176fe0a78218b898a684)

to branch 'i2p.i2p.zzz.jetty6' (head 960f416b20e26662b1b5b30468a85dbb25f09ffd)
This commit is contained in:
zzz
2012-01-22 18:30:41 +00:00
135 changed files with 4343 additions and 6999 deletions

View File

@ -21,7 +21,12 @@
<pathelement location="../../../core/java/build/obj" />
<pathelement location="../../../router/java/build/obj" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="../../jetty/jettylib/jetty-sslengine.jar" />
<pathelement location="../../jetty/jettylib/jetty-java5-threadpool.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
<pathelement location="../../systray/java/build/obj" />
<pathelement location="../../systray/java/lib/systray4j.jar" />
<pathelement location="../../desktopgui/build" />
@ -54,7 +59,12 @@
<pathelement location="../../../core/java/build/i2p.jar" />
<pathelement location="../../../router/java/build/router.jar" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="../../jetty/jettylib/jetty-sslengine.jar" />
<pathelement location="../../jetty/jettylib/jetty-java5-threadpool.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
<pathelement location="../../systray/java/build/systray.jar" />
<pathelement location="../../systray/java/lib/systray4j.jar" />
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
@ -236,7 +246,9 @@
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="../../jetty/jettylib/ant.jar" />
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
<pathelement location="../../systray/java/build/obj" />
<pathelement location="../../systray/java/lib/systray4j.jar" />
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
@ -269,6 +281,11 @@
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="../../jetty/jettylib/jetty-sslengine.jar" />
<pathelement location="../../jetty/jettylib/jetty-java5-threadpool.jar" />
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />
<pathelement location="../../systray/java/build/obj" />
<pathelement location="../../systray/java/lib/systray4j.jar" />
<pathelement location="../../desktopgui/dist/desktopgui.jar" />

View File

@ -14,7 +14,7 @@ import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.router.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.ContextHandlerCollection;
/**
* Saves changes to clients.config or webapps.config
@ -290,7 +290,7 @@ public class ConfigClientsHandler extends FormHandler {
* requested and add the .war to that one
*/
private void startWebApp(String app) {
Server s = WebAppStarter.getConsoleServer();
ContextHandlerCollection s = WebAppStarter.getConsoleServer();
if (s != null) {
try {
File path = new File(_context.getBaseDir(), "webapps");

View File

@ -4,11 +4,13 @@ import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.i2p.I2PAppContext;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.HttpResponse;
import org.mortbay.jetty.servlet.WebApplicationHandler;
import org.mortbay.jetty.webapp.WebAppContext;
/**
* Convert foo.jsp to foo_xx.jsp for language xx.
@ -19,12 +21,12 @@ import org.mortbay.jetty.servlet.WebApplicationHandler;
*
* @author zzz
*/
public class LocaleWebAppHandler extends WebApplicationHandler
public class LocaleWebAppHandler extends WebAppContext
{
private final I2PAppContext _context;
public LocaleWebAppHandler(I2PAppContext ctx) {
super();
public LocaleWebAppHandler(I2PAppContext ctx, String path, String warPath) {
super(warPath, path);
_context = ctx;
}
@ -36,13 +38,13 @@ public class LocaleWebAppHandler extends WebApplicationHandler
*/
@Override
public void handle(String pathInContext,
String pathParams,
HttpRequest httpRequest,
HttpResponse httpResponse)
throws IOException
HttpServletRequest httpRequest,
HttpServletResponse httpResponse,
int dispatch)
throws IOException, ServletException
{
// Handle OPTIONS (nothing to override)
if (HttpRequest.__OPTIONS.equals(httpRequest.getMethod()))
if ("OPTIONS".equals(httpRequest.getMethod()))
{
handleOptions(httpRequest, httpResponse);
return;
@ -74,7 +76,7 @@ public class LocaleWebAppHandler extends WebApplicationHandler
if (lang != null && lang.length() > 0 && !lang.equals("en")) {
String testPath = pathInContext.substring(0, len - 4) + '_' + lang + ".jsp";
// Do we have a servlet for the new path that isn't the catchall *.jsp?
Map.Entry servlet = getHolderEntry(testPath);
Map.Entry servlet = getServletHandler().getHolderEntry(testPath);
if (servlet != null) {
String servletPath = (String) servlet.getKey();
if (servletPath != null && !servletPath.startsWith("*")) {
@ -87,7 +89,7 @@ public class LocaleWebAppHandler extends WebApplicationHandler
}
}
//System.err.println("New path: " + newPath);
super.handle(newPath, pathParams, httpRequest, httpResponse);
super.handle(newPath, httpRequest, httpResponse, dispatch);
//System.err.println("Was handled? " + httpRequest.isHandled());
}
@ -95,22 +97,24 @@ public class LocaleWebAppHandler extends WebApplicationHandler
* Overrides method in ServletHandler
* @since 0.8
*/
/**** not in Jetty 6
@Override
public void handleTrace(HttpRequest request,
HttpResponse response)
public void handleTrace(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
response.sendError(HttpResponse.__405_Method_Not_Allowed);
response.sendError(405);
}
****/
/**
* Not an override
* @since 0.8
*/
public void handleOptions(HttpRequest request,
HttpResponse response)
public void handleOptions(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
response.sendError(HttpResponse.__405_Method_Not_Allowed);
response.sendError(405);
}
}

View File

@ -6,7 +6,7 @@ import java.util.List;
import net.i2p.util.FileUtil;
import net.i2p.util.VersionComparator;
import org.mortbay.http.Version;
import org.mortbay.jetty.Server;
import org.tanukisoftware.wrapper.WrapperManager;
public class LogsHelper extends HelperBase {
@ -15,19 +15,12 @@ public class LogsHelper extends HelperBase {
/** @since 0.8.12 */
public String getJettyVersion() {
return jettyVersion();
return Server.getVersion();
}
/** @since 0.8.13 */
static String jettyVersion() {
try {
String rv = Version.getImplVersion();
if (rv.startsWith("Jetty/"))
rv = rv.substring(6);
return rv;
} catch (Throwable t) {
return "unknown";
}
return Server.getVersion();
}
public String getLogs() {

View File

@ -32,7 +32,7 @@ import net.i2p.util.Log;
import net.i2p.util.Translate;
import net.i2p.util.VersionComparator;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.ContextHandlerCollection;
/**
@ -254,7 +254,7 @@ public class PluginStarter implements Runnable {
}
// start console webapps in console/webapps
Server server = WebAppStarter.getConsoleServer();
ContextHandlerCollection server = WebAppStarter.getConsoleServer();
if (server != null) {
File consoleDir = new File(pluginDir, "console");
Properties wprops = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
@ -354,8 +354,8 @@ public class PluginStarter implements Runnable {
}
// stop console webapps in console/webapps
Server server = WebAppStarter.getConsoleServer();
if (server != null) {
//ContextHandlerCollection server = WebAppStarter.getConsoleServer();
//if (server != null) {
/*
File consoleDir = new File(pluginDir, "console");
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
@ -375,11 +375,11 @@ public class PluginStarter implements Runnable {
Iterator <String> wars = pluginWars.get(appName).iterator();
while (wars.hasNext()) {
String warName = wars.next();
WebAppStarter.stopWebApp(server, warName);
WebAppStarter.stopWebApp(warName);
}
pluginWars.get(appName).clear();
}
}
//}
// remove summary bar link
Properties props = pluginProperties(ctx, appName);

View File

@ -11,12 +11,18 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import net.i2p.I2PAppContext;
import net.i2p.apps.systray.SysTray;
import net.i2p.data.Base32;
import net.i2p.data.DataHelper;
import net.i2p.desktopgui.Main;
import net.i2p.jetty.I2PLogger;
import net.i2p.router.RouterContext;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
@ -26,25 +32,41 @@ import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.ShellCommand;
import net.i2p.util.VersionComparator;
import org.mortbay.http.DigestAuthenticator;
import org.mortbay.http.HashUserRealm;
import org.mortbay.http.NCSARequestLog;
import org.mortbay.http.SecurityConstraint;
import org.mortbay.http.SocketListener;
import org.mortbay.http.SslListener;
import org.mortbay.http.handler.SecurityHandler;
import org.mortbay.jetty.AbstractConnector;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.NCSARequestLog;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.WebApplicationContext;
import org.mortbay.jetty.servlet.WebApplicationHandler;
import org.mortbay.util.InetAddrPort;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.handler.RequestLogHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.DigestAuthenticator;
import org.mortbay.jetty.security.HashUserRealm;
import org.mortbay.jetty.security.Constraint;
import org.mortbay.jetty.security.ConstraintMapping;
import org.mortbay.jetty.security.SecurityHandler;
import org.mortbay.jetty.security.SslSelectChannelConnector;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.jetty.servlet.SessionHandler;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.log.Log;
import org.mortbay.thread.QueuedThreadPool;
import org.mortbay.thread.concurrent.ThreadPool;
/**
* Start the router console.
*/
public class RouterConsoleRunner {
private Server _server;
private static Server _server;
private String _listenPort;
private String _listenHost;
private String _sslListenPort;
private String _sslListenHost;
private String _webAppsDir;
private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile";
private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
private static final DigestAuthenticator authenticator = new DigestAuthenticator();
@ -59,6 +81,11 @@ public class RouterConsoleRunner {
private static final String DEFAULT_WEBAPPS_DIR = "./webapps/";
private static final String USAGE = "Bad RouterConsoleRunner arguments, check clientApp.0.args in your clients.config file! " +
"Usage: [[port host[,host]] [-s sslPort [host[,host]]] [webAppsDir]]";
private static final int MIN_THREADS = 1;
private static final int MAX_THREADS = 24;
private static final int MAX_IDLE_TIME = 90*1000;
private static final String THREAD_NAME = "RouterConsole Jetty";
static {
System.setProperty("org.mortbay.http.Version.paranoid", "true");
@ -137,6 +164,15 @@ public class RouterConsoleRunner {
runner.startConsole();
}
/**
* SInce _server is now static
* @return may be null or stopped perhaps
* @since Jetty 6 since it doesn't have Server.getServers()
*/
static Server getConsoleServer() {
return _server;
}
private static void startTrayApp() {
try {
//TODO: move away from routerconsole into a separate application.
@ -160,6 +196,24 @@ public class RouterConsoleRunner {
}
}
/**
* http://irc.codehaus.org/display/JETTY/Porting+to+jetty6
*
*<pre>
* Server
* HandlerCollection
* ContextHandlerCollection
* WebAppContext (i.e. ContextHandler)
* SessionHandler
* SecurityHandler
* ServletHandler
* servlets...
* WebAppContext
* ...
* DefaultHandler
* RequestLogHandler (opt)
*</pre>
*/
public void startConsole() {
File workDir = new SecureDirectory(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
@ -169,9 +223,37 @@ public class RouterConsoleRunner {
if (!workDirCreated)
System.err.println("ERROR: Unable to create Jetty temporary work directory");
//try {
// Log.setLog(new I2PLogger(I2PAppContext.getGlobalContext()));
//} catch (Throwable t) {
// System.err.println("INFO: I2P Jetty logging class not found, logging to wrapper log");
//}
// This way it doesn't try to load Slf4jLog first
System.setProperty("org.mortbay.log.class", "net.i2p.jetty.I2PLogger");
// so Jetty can find WebAppConfiguration
System.setProperty("jetty.class.path", I2PAppContext.getGlobalContext().getBaseDir() + "/lib/routerconsole.jar");
_server = new Server();
_server.setGracefulShutdown(1000);
try {
ThreadPool ctp = new CustomThreadPoolExecutor();
ctp.prestartAllCoreThreads();
_server.setThreadPool(ctp);
} catch (Throwable t) {
// class not found...
System.out.println("INFO: Jetty concurrent ThreadPool unavailable, using QueuedThreadPool");
QueuedThreadPool qtp = new QueuedThreadPool(MAX_THREADS);
qtp.setMinThreads(MIN_THREADS);
qtp.setMaxIdleTimeMs(MAX_IDLE_TIME);
_server.setThreadPool(qtp);
}
HandlerCollection hColl = new HandlerCollection();
ContextHandlerCollection chColl = new ContextHandlerCollection();
_server.addHandler(hColl);
hColl.addHandler(chColl);
hColl.addHandler(new DefaultHandler());
String log = I2PAppContext.getGlobalContext().getProperty("routerconsole.log");
if (log != null) {
@ -179,8 +261,10 @@ public class RouterConsoleRunner {
if (!logFile.isAbsolute())
logFile = new File(I2PAppContext.getGlobalContext().getLogDir(), "logs/" + log);
try {
_server.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
} catch (IOException ioe) {
RequestLogHandler rhl = new RequestLogHandler();
rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
hColl.addHandler(rhl);
} catch (Exception ioe) {
System.err.println("ERROR: Unable to create Jetty log: " + ioe);
}
}
@ -203,8 +287,8 @@ public class RouterConsoleRunner {
if (!_webAppsDir.endsWith("/"))
_webAppsDir += '/';
List<String> notStarted = new ArrayList();
WebApplicationHandler baseHandler = null;
WebAppContext rootWebApp = null;
ServletHandler rootServletHandler = null;
try {
int boundAddresses = 0;
@ -219,17 +303,17 @@ public class RouterConsoleRunner {
// _server.addListener('[' + host + "]:" + _listenPort);
//else
// _server.addListener(host + ':' + _listenPort);
InetAddrPort iap = new InetAddrPort(host, lport);
SocketListener lsnr = new SocketListener(iap);
lsnr.setMinThreads(1); // default 2
lsnr.setMaxThreads(24); // default 256
lsnr.setMaxIdleTimeMs(90*1000); // default 10 sec
// Use AbstractConnector instead of Connector so we can do setName()
AbstractConnector lsnr = new SelectChannelConnector();
lsnr.setHost(host);
lsnr.setPort(lport);
lsnr.setMaxIdleTime(90*1000); // default 10 sec
lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
_server.addListener(lsnr);
_server.addConnector(lsnr);
boundAddresses++;
} catch (NumberFormatException nfe) {
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + nfe);
} catch (IOException ioe) { // this doesn't seem to work, exceptions don't happen until start() below
} catch (Exception ioe) { // this doesn't seem to work, exceptions don't happen until start() below
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
}
}
@ -254,19 +338,20 @@ public class RouterConsoleRunner {
while (tok.hasMoreTokens()) {
String host = tok.nextToken().trim();
// doing it this way means we don't have to escape an IPv6 host with []
InetAddrPort iap = new InetAddrPort(host, sslPort);
try {
SslListener ssll = new SslListener(iap);
// TODO if class not found use SslChannelConnector
// Sadly there's no common base class with the ssl methods in it
SslSelectChannelConnector ssll = new SslSelectChannelConnector();
ssll.setHost(host);
ssll.setPort(sslPort);
// the keystore path and password
ssll.setKeystore(keyStore.getAbsolutePath());
ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
// the X.509 cert password (if not present, verifyKeyStore() returned false)
ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
ssll.setMinThreads(1); // default 2
ssll.setMaxThreads(24); // default 256
ssll.setMaxIdleTimeMs(90*1000); // default 10 sec
ssll.setMaxIdleTime(90*1000); // default 10 sec
ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
_server.addListener(ssll);
_server.addConnector(ssll);
boundAddresses++;
} catch (Exception e) { // probably no exceptions at this point
System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
@ -282,47 +367,25 @@ public class RouterConsoleRunner {
System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
return;
}
_server.setRootWebApp(ROUTERCONSOLE);
WebApplicationContext wac = _server.addWebApplication("/", _webAppsDir + ROUTERCONSOLE + ".war");
rootWebApp = new LocaleWebAppHandler(I2PAppContext.getGlobalContext(),
"/", _webAppsDir + ROUTERCONSOLE + ".war");
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
(_listenPort != null ? _listenPort : _sslListenPort));
tmpdir.mkdir();
wac.setTempDirectory(tmpdir);
baseHandler = new LocaleWebAppHandler(I2PAppContext.getGlobalContext());
wac.addHandler(0, baseHandler);
initialize(wac);
File dir = new File(_webAppsDir);
String fileNames[] = dir.list(WarFilenameFilter.instance());
if (fileNames != null) {
for (int i = 0; i < fileNames.length; i++) {
try {
String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
String enabled = props.getProperty(PREFIX + appName + ENABLED);
if (! "false".equals(enabled)) {
String path = new File(dir, fileNames[i]).getCanonicalPath();
tmpdir = new SecureDirectory(workDir, appName + "-" +
(_listenPort != null ? _listenPort : _sslListenPort));
WebAppStarter.addWebApp(I2PAppContext.getGlobalContext(), _server, appName, path, tmpdir);
rootWebApp.setTempDirectory(tmpdir);
rootWebApp.setSessionHandler(new SessionHandler());
rootServletHandler = new ServletHandler();
rootWebApp.setServletHandler(rootServletHandler);
initialize(rootWebApp);
chColl.addHandler(rootWebApp);
if (enabled == null) {
// do this so configclients.jsp knows about all apps from reading the config
props.setProperty(PREFIX + appName + ENABLED, "true");
rewrite = true;
}
} else {
notStarted.add(appName);
}
} catch (IOException ioe) {
System.err.println("Error resolving '" + fileNames[i] + "' in '" + dir);
}
}
}
} catch (IOException ioe) {
} catch (Exception ioe) {
ioe.printStackTrace();
}
if (rewrite)
storeWebAppProperties(props);
try {
// start does a mapContexts()
_server.start();
} catch (Throwable me) {
// NoClassFoundDefError from a webapp is a throwable, not an exception
@ -335,14 +398,61 @@ public class RouterConsoleRunner {
me.printStackTrace();
}
if (baseHandler != null) {
// Start all the other webapps after the server is up,
// so things start faster.
// Jetty 6 starts the connector before the router console is ready
// This also prevents one webapp from breaking the whole thing
List<String> notStarted = new ArrayList();
if (_server.isRunning()) {
File dir = new File(_webAppsDir);
String fileNames[] = dir.list(WarFilenameFilter.instance());
if (fileNames != null) {
for (int i = 0; i < fileNames.length; i++) {
String appName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
String enabled = props.getProperty(PREFIX + appName + ENABLED);
if (! "false".equals(enabled)) {
try {
String path = new File(dir, fileNames[i]).getCanonicalPath();
WebAppStarter.startWebApp(I2PAppContext.getGlobalContext(), chColl, appName, path);
if (enabled == null) {
// do this so configclients.jsp knows about all apps from reading the config
props.setProperty(PREFIX + appName + ENABLED, "true");
rewrite = true;
}
} catch (Throwable t) {
System.err.println("ERROR: Failed to start " + appName + ' ' + t);
t.printStackTrace();
notStarted.add(appName);
}
} else {
notStarted.add(appName);
}
}
}
} else {
System.err.println("ERROR: Router console did not start, not starting webapps");
}
if (rewrite)
storeWebAppProperties(props);
if (rootServletHandler != null && notStarted.size() > 0) {
// map each not-started webapp to the error page
ServletHolder noWebApp = rootServletHandler.getServlet("net.i2p.router.web.jsp.nowebapp_jsp");
for (int i = 0; i < notStarted.size(); i++) {
// we want a new handler for each one since if the webapp is started we remove the handler???
try {
baseHandler.mapPathToServlet('/' + notStarted.get(i) + "/*",
"net.i2p.router.web.jsp.nowebapp_jsp");
if (noWebApp != null) {
String path = '/' + notStarted.get(i);
// LocaleWebAppsHandler adds a .jsp
rootServletHandler.addServletWithMapping(noWebApp, path + ".jsp");
rootServletHandler.addServletWithMapping(noWebApp, path + "/*");
} else {
System.err.println("Can't find nowebapp.jsp?");
}
} catch (Throwable me) {
System.err.println(me);
me.printStackTrace();
}
}
}
@ -458,18 +568,22 @@ public class RouterConsoleRunner {
return success;
}
static void initialize(WebApplicationContext context) {
static void initialize(WebAppContext context) {
SecurityHandler sec = new SecurityHandler();
List<ConstraintMapping> constraints = new ArrayList(4);
String password = getPassword();
if (password != null) {
HashUserRealm realm = new HashUserRealm("i2prouter");
realm.put("admin", password);
realm.addUserToRole("admin", "routerAdmin");
context.setRealm(realm);
context.setAuthenticator(authenticator);
context.addHandler(0, new SecurityHandler());
SecurityConstraint constraint = new SecurityConstraint("admin", "routerAdmin");
sec.setUserRealm(realm);
sec.setAuthenticator(authenticator);
Constraint constraint = new Constraint("admin", "routerAdmin");
constraint.setAuthenticate(true);
context.addSecurityConstraint("/", constraint);
ConstraintMapping cm = new ConstraintMapping();
cm.setConstraint(constraint);
cm.setPathSpec("/");
constraints.add(cm);
}
// This forces a '403 Forbidden' response for TRACE and OPTIONS unless the
@ -481,12 +595,27 @@ public class RouterConsoleRunner {
// The other strange methods - PUT, DELETE, MOVE - are disabled by default
// See also:
// http://old.nabble.com/Disable-HTTP-TRACE-in-Jetty-5.x-td12412607.html
SecurityConstraint sc = new SecurityConstraint();
sc.setName("No trace or options");
sc.addMethod("TRACE");
sc.addMethod("OPTIONS");
sc.setAuthenticate(true);
context.addSecurityConstraint("/*", sc) ;
Constraint sc = new Constraint();
sc.setName("No trace");
ConstraintMapping cm = new ConstraintMapping();
cm.setMethod("TRACE");
cm.setConstraint(sc);
cm.setPathSpec("/");
constraints.add(cm);
sc = new Constraint();
sc.setName("No options");
cm = new ConstraintMapping();
cm.setMethod("OPTIONS");
cm.setConstraint(sc);
cm.setPathSpec("/");
constraints.add(cm);
ConstraintMapping cmarr[] = constraints.toArray(new ConstraintMapping[constraints.size()]);
sec.setConstraintMappings(cmarr);
context.setSecurityHandler(sec);
}
static String getPassword() {
@ -511,11 +640,11 @@ public class RouterConsoleRunner {
}
/** @since 0.8.8 */
private class ServerShutdown implements Runnable {
private static class ServerShutdown implements Runnable {
public void run() {
try {
_server.stop();
} catch (InterruptedException ie) {}
} catch (Exception ie) {}
}
}
@ -574,4 +703,31 @@ public class RouterConsoleRunner {
}
}
/**
* Just to set the name and set Daemon
* @since Jetty 6
*/
private static class CustomThreadPoolExecutor extends ThreadPool {
public CustomThreadPoolExecutor() {
super(MIN_THREADS, MAX_THREADS, MAX_IDLE_TIME, TimeUnit.MILLISECONDS,
new SynchronousQueue(), new CustomThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
/**
* Just to set the name and set Daemon
* @since Jetty 6
*/
private static class CustomThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread rv = Executors.defaultThreadFactory().newThread(r);
rv.setName(THREAD_NAME);
rv.setDaemon(true);
return rv;
}
}
}

View File

@ -6,7 +6,8 @@ import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import org.mortbay.jetty.servlet.WebApplicationContext;
import org.mortbay.jetty.webapp.Configuration;
import org.mortbay.jetty.webapp.WebAppContext;
/**
@ -31,16 +32,16 @@ import org.mortbay.jetty.servlet.WebApplicationContext;
* @since 0.7.12
* @author zzz
*/
public class WebAppConfiguration implements WebApplicationContext.Configuration {
private WebApplicationContext _wac;
public class WebAppConfiguration implements Configuration {
private WebAppContext _wac;
private static final String CLASSPATH = ".classpath";
public void setWebApplicationContext(WebApplicationContext context) {
public void setWebAppContext(WebAppContext context) {
_wac = context;
}
public WebApplicationContext getWebApplicationContext() {
public WebAppContext getWebAppContext() {
return _wac;
}
@ -87,10 +88,16 @@ public class WebAppConfiguration implements WebApplicationContext.Configuration
else
path = dir.getAbsolutePath() + '/' + elem;
System.err.println("Adding " + path + " to classpath for " + appName);
_wac.addClassPath(path);
_wac.setExtraClasspath(path);
}
}
public void configureDefaults() {}
public void configureWebApp() {}
/** @since Jetty 6 */
public void deconfigureWebApp() {}
/** @since Jetty 6 */
public void configureClassLoader() {}
}

View File

@ -14,10 +14,12 @@ import net.i2p.util.Log;
import net.i2p.util.SecureDirectory;
import net.i2p.util.PortMapper;
import org.mortbay.http.HttpContext;
import org.mortbay.http.HttpListener;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.WebApplicationContext;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
/**
@ -49,9 +51,10 @@ public class WebAppStarter {
* adds and starts
* @throws just about anything, caller would be wise to catch Throwable
*/
static void startWebApp(I2PAppContext ctx, Server server, String appName, String warPath) throws Exception {
static void startWebApp(I2PAppContext ctx, ContextHandlerCollection server,
String appName, String warPath) throws Exception {
File tmpdir = new SecureDirectory(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
WebApplicationContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
WebAppContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
_log.debug("Loading war from: " + warPath);
wac.start();
}
@ -61,12 +64,13 @@ public class WebAppStarter {
* This is used only by RouterConsoleRunner, which adds all the webapps first
* and then starts all at once.
*/
static WebApplicationContext addWebApp(I2PAppContext ctx, Server server, String appName, String warPath, File tmpdir) throws IOException {
static WebAppContext addWebApp(I2PAppContext ctx, ContextHandlerCollection server,
String appName, String warPath, File tmpdir) throws IOException {
// Jetty will happily load one context on top of another without stopping
// the first one, so we remove any previous one here
try {
stopWebApp(server, appName);
stopWebApp(appName);
} catch (Throwable t) {}
// To avoid ZipErrors from JarURLConnetion caching,
@ -91,7 +95,7 @@ public class WebAppStarter {
warPath = tmpPath;
}
WebApplicationContext wac = server.addWebApplication("/"+ appName, warPath);
WebAppContext wac = new WebAppContext(warPath, "/"+ appName);
tmpdir.mkdir();
wac.setTempDirectory(tmpdir);
@ -101,12 +105,14 @@ public class WebAppStarter {
// see WebAppConfiguration for info
String[] classNames = server.getWebApplicationConfigurationClassNames();
String[] classNames = wac.getConfigurationClasses();
String[] newClassNames = new String[classNames.length + 1];
for (int j = 0; j < classNames.length; j++)
newClassNames[j] = classNames[j];
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
wac.setConfigurationClassNames(newClassNames);
wac.setConfigurationClasses(newClassNames);
server.addHandler(wac);
server.mapContexts();
return wac;
}
@ -114,42 +120,55 @@ public class WebAppStarter {
* stop it and remove the context
* @throws just about anything, caller would be wise to catch Throwable
*/
static void stopWebApp(Server server, String appName) {
// this will return a new context if one does not exist
HttpContext wac = server.getContext('/' + appName);
static void stopWebApp(String appName) {
ContextHandler wac = getWebApp(appName);
if (wac == null)
return;
try {
// false -> not graceful
wac.stop(false);
} catch (InterruptedException ie) {}
// not graceful is default in Jetty 6?
wac.stop();
} catch (Exception ie) {}
ContextHandlerCollection server = getConsoleServer();
if (server == null)
return;
try {
server.removeContext(wac);
server.removeHandler(wac);
server.mapContexts();
} catch (IllegalStateException ise) {}
}
static boolean isWebAppRunning(String appName) {
Server server = WebAppStarter.getConsoleServer();
if (server == null)
ContextHandler wac = getWebApp(appName);
if (wac == null)
return false;
// this will return a new context if one does not exist
HttpContext wac = server.getContext('/' + appName);
return wac.isStarted();
}
/** see comments in ConfigClientsHandler */
static Server getConsoleServer() {
PortMapper pm = I2PAppContext.getGlobalContext().portMapper();
int p1 = pm.getPort(PortMapper.SVC_CONSOLE);
int p2 = pm.getPort(PortMapper.SVC_HTTPS_CONSOLE);
Collection c = Server.getHttpServers();
for (int i = 0; i < c.size(); i++) {
Server s = (Server) c.toArray()[i];
HttpListener[] hl = s.getListeners();
for (int j = 0; j < hl.length; j++) {
int port = hl[j].getPort();
if (port == p1 || port == p2)
return s;
}
/** @since Jetty 6 */
static ContextHandler getWebApp(String appName) {
ContextHandlerCollection server = getConsoleServer();
if (server == null)
return null;
Handler handlers[] = server.getHandlers();
if (handlers == null)
return null;
String path = '/'+ appName;
for (int i = 0; i < handlers.length; i++) {
ContextHandler ch = (ContextHandler) handlers[i];
if (path.equals(ch.getContextPath()))
return ch;
}
return null;
}
/** see comments in ConfigClientsHandler */
static ContextHandlerCollection getConsoleServer() {
Server s = RouterConsoleRunner.getConsoleServer();
if (s == null)
return null;
Handler h = s.getChildHandlerByClass(ContextHandlerCollection.class);
if (h == null)
return null;
return (ContextHandlerCollection) h;
}
}