First cut at migrating to Jetty 6 and prep for using an external
Jetty 6 package. - Add several jars from the Jetty 6 distribution - Update jetty.xml - Add context XML files - Update WorkingDir to migrate the content XML files - Update RouterConsoleRunner and LocaleWebAppHandler - Remove all old Jetty 5.1.15 local mods; this will break Seedless using a custom Server() constructor - Update I2PRequestLog to be a mod of NCSARequestLog from 6.1.26 - Put I2PRequestLog in its own jar - Copy MultiPartRequest and other required classes from Jetty 5.1.15 and add it to susimail, as the replacement MultiPartFilter in Jetty 6 is difficult to migrate to, and does not support content-type - Update i2psnark for Jetty 6 - Disable i2psnark RunStandalone, unused and instantiated Jetty 5 - Fix up all webapp build.xml to reference new jars Not yet working: Plugin/webapp run detection and stopping, eepsite CGI Not well tested: Plugins, classpaths, webapps
@ -19,6 +19,7 @@
|
|||||||
<pathelement location="../../ministreaming/java/build/obj" />
|
<pathelement location="../../ministreaming/java/build/obj" />
|
||||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||||
</classpath>
|
</classpath>
|
||||||
</depend>
|
</depend>
|
||||||
</target>
|
</target>
|
||||||
@ -34,7 +35,7 @@
|
|||||||
debug="true" deprecation="on" source="1.5" target="1.5"
|
debug="true" deprecation="on" source="1.5" target="1.5"
|
||||||
destdir="./build/obj"
|
destdir="./build/obj"
|
||||||
includeAntRuntime="false"
|
includeAntRuntime="false"
|
||||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" >
|
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
|
||||||
<compilerarg line="${javac.compilerargs}" />
|
<compilerarg line="${javac.compilerargs}" />
|
||||||
</javac>
|
</javac>
|
||||||
</target>
|
</target>
|
||||||
|
@ -43,17 +43,16 @@ import org.klomp.snark.SnarkManager;
|
|||||||
import org.klomp.snark.Storage;
|
import org.klomp.snark.Storage;
|
||||||
import org.klomp.snark.TrackerClient;
|
import org.klomp.snark.TrackerClient;
|
||||||
|
|
||||||
import org.mortbay.http.HttpResponse;
|
import org.mortbay.jetty.servlet.DefaultServlet;
|
||||||
import org.mortbay.jetty.servlet.Default;
|
import org.mortbay.resource.Resource;
|
||||||
import org.mortbay.util.Resource;
|
import org.mortbay.util.URIUtil;
|
||||||
import org.mortbay.util.URI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We extend Default instead of HTTPServlet so we can handle
|
* We extend Default instead of HTTPServlet so we can handle
|
||||||
* i2psnark/ file requests with http:// instead of the flaky and
|
* i2psnark/ file requests with http:// instead of the flaky and
|
||||||
* often-blocked-by-the-browser file://
|
* often-blocked-by-the-browser file://
|
||||||
*/
|
*/
|
||||||
public class I2PSnarkServlet extends Default {
|
public class I2PSnarkServlet extends DefaultServlet {
|
||||||
private I2PAppContext _context;
|
private I2PAppContext _context;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private SnarkManager _manager;
|
private SnarkManager _manager;
|
||||||
@ -99,13 +98,17 @@ public class I2PSnarkServlet extends Default {
|
|||||||
* and we can't get any resources (like icons) out of the .war
|
* and we can't get any resources (like icons) out of the .war
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Resource getResource(String pathInContext) throws IOException
|
public Resource getResource(String pathInContext)
|
||||||
{
|
{
|
||||||
if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") ||
|
if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") ||
|
||||||
pathInContext.equals("/index.html") || pathInContext.startsWith("/_icons/"))
|
pathInContext.equals("/index.html") || pathInContext.startsWith("/_icons/"))
|
||||||
return super.getResource(pathInContext);
|
return super.getResource(pathInContext);
|
||||||
// files in the i2psnark/ directory
|
// files in the i2psnark/ directory
|
||||||
return _resourceBase.addPath(pathInContext);
|
try {
|
||||||
|
return _resourceBase.addPath(pathInContext);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new RuntimeException(ioe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,10 +116,11 @@ public class I2PSnarkServlet extends Default {
|
|||||||
* @since 0.8.3
|
* @since 0.8.3
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void handleGet(HttpServletRequest request, HttpServletResponse response, String pathInContext, Resource resource, boolean endsWithSlash) throws ServletException, IOException {
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
if (resource.getName().startsWith("jar:file:"))
|
////////////////////////////////////
|
||||||
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
//if (resource.getName().startsWith("jar:file:"))
|
||||||
super.handleGet(request, response, pathInContext, resource, endsWithSlash);
|
// response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
||||||
|
super.doGet(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +148,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
// since we are not overriding handle*(), do this here
|
// since we are not overriding handle*(), do this here
|
||||||
String method = req.getMethod();
|
String method = req.getMethod();
|
||||||
if (!(method.equals("GET") || method.equals("HEAD") || method.equals("POST"))) {
|
if (!(method.equals("GET") || method.equals("HEAD") || method.equals("POST"))) {
|
||||||
resp.sendError(HttpResponse.__405_Method_Not_Allowed);
|
resp.sendError(405);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_themePath = "/themes/snark/" + _manager.getTheme() + '/';
|
_themePath = "/themes/snark/" + _manager.getTheme() + '/';
|
||||||
@ -157,20 +161,20 @@ public class I2PSnarkServlet extends Default {
|
|||||||
if (path.endsWith("/")) {
|
if (path.endsWith("/")) {
|
||||||
// bypass the horrid Resource.getListHTML()
|
// bypass the horrid Resource.getListHTML()
|
||||||
String pathInfo = req.getPathInfo();
|
String pathInfo = req.getPathInfo();
|
||||||
String pathInContext = URI.addPaths(path, pathInfo);
|
String pathInContext = URIUtil.addPaths(path, pathInfo);
|
||||||
req.setCharacterEncoding("UTF-8");
|
req.setCharacterEncoding("UTF-8");
|
||||||
resp.setCharacterEncoding("UTF-8");
|
resp.setCharacterEncoding("UTF-8");
|
||||||
resp.setContentType("text/html; charset=UTF-8");
|
resp.setContentType("text/html; charset=UTF-8");
|
||||||
Resource resource = getResource(pathInContext);
|
Resource resource = getResource(pathInContext);
|
||||||
if (resource == null || (!resource.exists())) {
|
if (resource == null || (!resource.exists())) {
|
||||||
resp.sendError(HttpResponse.__404_Not_Found);
|
resp.sendError(404);
|
||||||
} else {
|
} else {
|
||||||
String base = URI.addPaths(req.getRequestURI(), "/");
|
String base = URIUtil.addPaths(req.getRequestURI(), "/");
|
||||||
String listing = getListHTML(resource, base, true, method.equals("POST") ? req.getParameterMap() : null);
|
String listing = getListHTML(resource, base, true, method.equals("POST") ? req.getParameterMap() : null);
|
||||||
if (listing != null)
|
if (listing != null)
|
||||||
resp.getWriter().write(listing);
|
resp.getWriter().write(listing);
|
||||||
else // shouldn't happen
|
else // shouldn't happen
|
||||||
resp.sendError(HttpResponse.__404_Not_Found);
|
resp.sendError(404);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
super.service(req, resp);
|
super.service(req, resp);
|
||||||
@ -1680,7 +1684,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
|
|
||||||
StringBuilder buf=new StringBuilder(4096);
|
StringBuilder buf=new StringBuilder(4096);
|
||||||
buf.append(DOCTYPE + "<HTML><HEAD><TITLE>");
|
buf.append(DOCTYPE + "<HTML><HEAD><TITLE>");
|
||||||
String title = URI.decodePath(base);
|
String title = URIUtil.decodePath(base);
|
||||||
if (title.startsWith("/i2psnark/"))
|
if (title.startsWith("/i2psnark/"))
|
||||||
title = title.substring("/i2psnark/".length());
|
title = title.substring("/i2psnark/".length());
|
||||||
|
|
||||||
@ -1783,7 +1787,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
.append(_("Priority")).append("</th>");
|
.append(_("Priority")).append("</th>");
|
||||||
buf.append("</tr></thead>\n");
|
buf.append("</tr></thead>\n");
|
||||||
buf.append("<tr><td colspan=\"" + (showPriority ? '4' : '3') + "\" class=\"ParentDir\"><A HREF=\"");
|
buf.append("<tr><td colspan=\"" + (showPriority ? '4' : '3') + "\" class=\"ParentDir\"><A HREF=\"");
|
||||||
buf.append(URI.addPaths(base,"../"));
|
buf.append(URIUtil.addPaths(base,"../"));
|
||||||
buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ")
|
buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ")
|
||||||
.append(_("Up to higher level directory")).append("</A></td></tr>\n");
|
.append(_("Up to higher level directory")).append("</A></td></tr>\n");
|
||||||
|
|
||||||
@ -1793,7 +1797,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
boolean showSaveButton = false;
|
boolean showSaveButton = false;
|
||||||
for (int i=0 ; i< ls.length ; i++)
|
for (int i=0 ; i< ls.length ; i++)
|
||||||
{
|
{
|
||||||
String encoded=URI.encodePath(ls[i]);
|
String encoded=URIUtil.encodePath(ls[i]);
|
||||||
// bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times)
|
// bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times)
|
||||||
// http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs
|
// http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs
|
||||||
// See resource.diff attachment
|
// See resource.diff attachment
|
||||||
@ -1849,9 +1853,9 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String path=URI.addPaths(base,encoded);
|
String path=URIUtil.addPaths(base,encoded);
|
||||||
if (item.isDirectory() && !path.endsWith("/"))
|
if (item.isDirectory() && !path.endsWith("/"))
|
||||||
path=URI.addPaths(path,"/");
|
path=URIUtil.addPaths(path,"/");
|
||||||
String icon = toIcon(item);
|
String icon = toIcon(item);
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
|
@ -31,6 +31,8 @@ public class RunStandalone {
|
|||||||
if (!workDirCreated)
|
if (!workDirCreated)
|
||||||
System.err.println("ERROR: Unable to create Jetty temporary work directory");
|
System.err.println("ERROR: Unable to create Jetty temporary work directory");
|
||||||
|
|
||||||
|
throw new RuntimeException("unsupported");
|
||||||
|
/****
|
||||||
try {
|
try {
|
||||||
_server = new Server("jetty-i2psnark.xml");
|
_server = new Server("jetty-i2psnark.xml");
|
||||||
// just blow up NPE if we don't have a context
|
// just blow up NPE if we don't have a context
|
||||||
@ -39,13 +41,17 @@ public class RunStandalone {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
throw new RuntimeException("unsupported");
|
||||||
|
/****
|
||||||
try {
|
try {
|
||||||
_server.stop();
|
_server.stop();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
ie.printStackTrace();
|
ie.printStackTrace();
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,7 @@
|
|||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.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/ant.jar" />
|
||||||
<pathelement location="build/i2ptunnel.jar" />
|
<pathelement location="build/i2ptunnel.jar" />
|
||||||
</classpath>
|
</classpath>
|
||||||
@ -190,6 +191,7 @@
|
|||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<pathelement location="build/i2ptunnel.jar" />
|
<pathelement location="build/i2ptunnel.jar" />
|
||||||
</classpath>
|
</classpath>
|
||||||
</javac>
|
</javac>
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project basedir="." default="all" name="jetty">
|
<project basedir="." default="all" name="jetty">
|
||||||
|
|
||||||
<property name="jetty.base" value="jetty-5.1.15" />
|
<property name="jetty.ver" value="6.1.26" />
|
||||||
<property name="jetty.sha1" value="3a7a3de50f86f0cdb23c33aec632ea7f44132c5e" />
|
<property name="jetty.base" value="jetty-${jetty.ver}" />
|
||||||
<property name="jetty.filename" value="${jetty.base}.tgz" />
|
<property name="jetty.sha1" value="9485913f1a1945a849a90f1a34853d22350bc524" />
|
||||||
<property name="jetty.url" value="http://dist.codehaus.org/jetty/jetty-5.1.x/${jetty.filename}" />
|
<property name="jetty.filename" value="${jetty.base}.zip" />
|
||||||
|
<property name="jetty.url" value="http://dist.codehaus.org/jetty/${jetty.base}/${jetty.filename}" />
|
||||||
<property name="verified.filename" value="verified.txt" />
|
<property name="verified.filename" value="verified.txt" />
|
||||||
<property name="javac.compilerargs" value="" />
|
<property name="javac.compilerargs" value="" />
|
||||||
|
|
||||||
@ -64,26 +65,46 @@
|
|||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="extractJettylib" unless="jetty.zip.extracted" >
|
<target name="extractJettylib" unless="jetty.zip.extracted" >
|
||||||
|
<!-- for .tgz -->
|
||||||
|
<!--
|
||||||
<gunzip src="${jetty.filename}" dest="jetty.tar" />
|
<gunzip src="${jetty.filename}" dest="jetty.tar" />
|
||||||
<untar src="jetty.tar" dest="." />
|
<untar src="jetty.tar" dest="." />
|
||||||
|
-->
|
||||||
|
<!-- for .zip -->
|
||||||
|
<unzip src="${jetty.filename}" dest="." />
|
||||||
<mkdir dir="jettylib" />
|
<mkdir dir="jettylib" />
|
||||||
<copy todir="jettylib" preservelastmodified="true" >
|
<!-- We copy everything to names without the version numbers so we
|
||||||
<fileset dir="${jetty.base}/lib">
|
can update them later. Where there was something similar in Jetty 5,
|
||||||
<include name="*.jar" />
|
we use the same names.
|
||||||
</fileset>
|
Reasons for inclusion:
|
||||||
<fileset dir="${jetty.base}/ext">
|
start.jar: Needed for clients.config startup of eepsites
|
||||||
<include name="ant.jar" />
|
jetty-util-xxx.jar: LifeCycle (base class for stuff), URIUtil (used in i2psnark)
|
||||||
<include name="commons-el.jar" />
|
jetty-sslengine-xxx.jar: SSL NIO Connector for console
|
||||||
<include name="commons-logging.jar" />
|
jetty-java5-threadpool-xxx.jar: Concurrent thread pool for eepsite
|
||||||
<include name="jasper-compiler.jar" />
|
commons-logging.jar: JspC compiler
|
||||||
<include name="jasper-runtime.jar" />
|
TODO which of these are available in the Ubuntu packages?
|
||||||
</fileset>
|
-->
|
||||||
</copy>
|
<copy preservelastmodified="true" file="${jetty.base}/lib/${jetty.base}.jar" tofile="jettylib/org.mortbay.jetty.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-util-${jetty.ver}.jar" tofile="jettylib/jetty-util.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/servlet-api-2.5-20081211.jar" tofile="jettylib/javax.servlet.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/ext/jetty-sslengine-${jetty.ver}.jar" tofile="jettylib/jetty-sslengine.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/ext/jetty-java5-threadpool-${jetty.ver}.jar" tofile="jettylib/jetty-threadpool.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/ant-1.6.5.jar" tofile="jettylib/ant.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/commons-el-1.0.jar" tofile="jettylib/commons-el.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jasper-compiler-5.5.15.jar" tofile="jettylib/jasper-compiler.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jasper-runtime-5.5.15.jar" tofile="jettylib/jasper-runtime.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/lib/jsp-2.0/jsp-api-2.0.jar" tofile="jettylib/jsp-api.jar" />
|
||||||
|
<copy preservelastmodified="true" file="${jetty.base}/start.jar" tofile="jettylib/jetty-start.jar" />
|
||||||
<delete file="jetty.tar" />
|
<delete file="jetty.tar" />
|
||||||
<delete dir="${jetty.base}" />
|
<delete dir="${jetty.base}" />
|
||||||
|
<!-- commons-logging.jar not in Jetty 6 but we have it in launch4j so copy it over, we need it
|
||||||
|
for org.apache.jasper.JspC compiler
|
||||||
|
-->
|
||||||
|
<copy preservelastmodified="true" file="../../installer/lib/launch4j/lib/commons-logging.jar" todir="jettylib/" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="build" depends="jar" />
|
<target name="build" depends="jar" />
|
||||||
|
|
||||||
<target name="builddep" />
|
<target name="builddep" />
|
||||||
<target name="compile" depends="builddep, ensureJettylib" >
|
<target name="compile" depends="builddep, ensureJettylib" >
|
||||||
<mkdir dir="./build" />
|
<mkdir dir="./build" />
|
||||||
@ -93,7 +114,7 @@
|
|||||||
debug="true" source="1.5" target="1.5"
|
debug="true" source="1.5" target="1.5"
|
||||||
destdir="./build/obj"
|
destdir="./build/obj"
|
||||||
includeAntRuntime="false"
|
includeAntRuntime="false"
|
||||||
classpath="./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar" >
|
classpath="./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-util.jar" >
|
||||||
<compilerarg line="${javac.compilerargs}" />
|
<compilerarg line="${javac.compilerargs}" />
|
||||||
</javac>
|
</javac>
|
||||||
</target>
|
</target>
|
||||||
@ -112,10 +133,13 @@
|
|||||||
</exec>
|
</exec>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<!-- With Jetty 5 we replaced classes in the jar, but with Jetty 6 we
|
||||||
|
put our stuff in its own jar so we can work with standard Jetty 6 packages
|
||||||
|
-->
|
||||||
<target name="jar" depends="compile, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
|
<target name="jar" depends="compile, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
|
||||||
<!-- set if unset -->
|
<!-- set if unset -->
|
||||||
<property name="workspace.changes.tr" value="" />
|
<property name="workspace.changes.tr" value="" />
|
||||||
<jar destfile="./jettylib/org.mortbay.jetty.jar" basedir="./build/obj" includes="**/*.class" update="true" >
|
<jar destfile="./jettylib/jetty-i2p.jar" basedir="./build/obj" includes="**/*.class" >
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||||
|
@ -1,505 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
|
|
||||||
// Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
package org.mortbay.http;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.mortbay.log.LogFactory;
|
|
||||||
import org.mortbay.util.DateCache;
|
|
||||||
import org.mortbay.util.LogSupport;
|
|
||||||
import org.mortbay.util.RolloverFileOutputStream;
|
|
||||||
import org.mortbay.util.StringUtil;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** NCSA HTTP Request Log.
|
|
||||||
* NCSA common or NCSA extended (combined) request log.
|
|
||||||
*
|
|
||||||
* Taken from 5.1.12 source and modded to change some private vars to protected
|
|
||||||
* so we can extend it for I2P.
|
|
||||||
*
|
|
||||||
* @version $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
|
|
||||||
* @author Tony Thompson
|
|
||||||
* @author Greg Wilkins
|
|
||||||
*/
|
|
||||||
public class NCSARequestLog implements RequestLog
|
|
||||||
{
|
|
||||||
protected static Log log = LogFactory.getLog(NCSARequestLog.class);
|
|
||||||
|
|
||||||
private String _filename;
|
|
||||||
private boolean _extended;
|
|
||||||
private boolean _append;
|
|
||||||
private int _retainDays;
|
|
||||||
private boolean _closeOut;
|
|
||||||
private boolean _preferProxiedForAddress;
|
|
||||||
private String _logDateFormat="dd/MMM/yyyy:HH:mm:ss ZZZ";
|
|
||||||
private Locale _logLocale=Locale.getDefault();
|
|
||||||
private String _logTimeZone=TimeZone.getDefault().getID();
|
|
||||||
private String[] _ignorePaths;
|
|
||||||
private boolean _logLatency=false;
|
|
||||||
private boolean _logCookies=false;
|
|
||||||
|
|
||||||
protected transient OutputStream _out;
|
|
||||||
protected transient OutputStream _fileOut;
|
|
||||||
protected transient DateCache _logDateCache;
|
|
||||||
protected transient PathMap _ignorePathMap;
|
|
||||||
protected transient Writer _writer;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
*/
|
|
||||||
public NCSARequestLog()
|
|
||||||
{
|
|
||||||
_extended=true;
|
|
||||||
_append=true;
|
|
||||||
_retainDays=31;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param filename Filename, which can be in
|
|
||||||
* rolloverFileOutputStream format
|
|
||||||
* @see org.mortbay.util.RolloverFileOutputStream
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public NCSARequestLog(String filename)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_extended=true;
|
|
||||||
_append=true;
|
|
||||||
_retainDays=31;
|
|
||||||
setFilename(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the log filename.
|
|
||||||
* @see NCSARequestLog#setRetainDays(int)
|
|
||||||
* @param filename The filename to use. If the filename contains the
|
|
||||||
* string "yyyy_mm_dd", then a RolloverFileOutputStream is used and the
|
|
||||||
* log is rolled over nightly and aged according setRetainDays. If no
|
|
||||||
* filename is set or a null filename
|
|
||||||
* passed, then requests are logged to System.err.
|
|
||||||
*/
|
|
||||||
public void setFilename(String filename)
|
|
||||||
{
|
|
||||||
if (filename!=null)
|
|
||||||
{
|
|
||||||
filename=filename.trim();
|
|
||||||
if (filename.length()==0)
|
|
||||||
filename=null;
|
|
||||||
}
|
|
||||||
_filename=filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the log filename.
|
|
||||||
* @see NCSARequestLog#getDatedFilename()
|
|
||||||
* @return The log filename without any date expansion.
|
|
||||||
*/
|
|
||||||
public String getFilename()
|
|
||||||
{
|
|
||||||
return _filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the dated log filename.
|
|
||||||
* @see NCSARequestLog#getFilename()
|
|
||||||
* @return The log filename with any date encoding expanded.
|
|
||||||
*/
|
|
||||||
public String getDatedFilename()
|
|
||||||
{
|
|
||||||
if (_fileOut instanceof RolloverFileOutputStream)
|
|
||||||
return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param format The date format to use within the log file.
|
|
||||||
*/
|
|
||||||
public void setLogDateFormat(String format)
|
|
||||||
{
|
|
||||||
_logDateFormat=format;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return The date format to use within the log file.
|
|
||||||
*/
|
|
||||||
public String getLogDateFormat()
|
|
||||||
{
|
|
||||||
return _logDateFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param tz The date format timezone to use within the log file.
|
|
||||||
*/
|
|
||||||
public void setLogTimeZone(String tz)
|
|
||||||
{
|
|
||||||
_logTimeZone=tz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return The date format timezone to use within the log file.
|
|
||||||
*/
|
|
||||||
public String getLogTimeZone()
|
|
||||||
{
|
|
||||||
return _logTimeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return The number of days to retain rollovered log files.
|
|
||||||
*/
|
|
||||||
public int getRetainDays()
|
|
||||||
{
|
|
||||||
return _retainDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param retainDays The number of days to retain rollovered log files.
|
|
||||||
*/
|
|
||||||
public void setRetainDays(int retainDays)
|
|
||||||
{
|
|
||||||
_retainDays = retainDays;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return True if NCSA extended format is to be used.
|
|
||||||
*/
|
|
||||||
public boolean isExtended()
|
|
||||||
{
|
|
||||||
return _extended;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param e True if NCSA extended format is to be used.
|
|
||||||
*/
|
|
||||||
public void setExtended(boolean e)
|
|
||||||
{
|
|
||||||
_extended=e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return True if logs are appended to existing log files.
|
|
||||||
*/
|
|
||||||
public boolean isAppend()
|
|
||||||
{
|
|
||||||
return _append;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param a True if logs are appended to existing log files.
|
|
||||||
*/
|
|
||||||
public void setAppend(boolean a)
|
|
||||||
{
|
|
||||||
_append=a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @deprecated ignored
|
|
||||||
*/
|
|
||||||
public void setBuffered(boolean b)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set which paths to ignore.
|
|
||||||
*
|
|
||||||
* @param ignorePaths Array of path specifications to ignore
|
|
||||||
*/
|
|
||||||
public void setIgnorePaths(String[] ignorePaths)
|
|
||||||
{
|
|
||||||
// Contributed by Martin Vilcans (martin@jadestone.se)
|
|
||||||
_ignorePaths = ignorePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public String[] getIgnorePaths()
|
|
||||||
{
|
|
||||||
return _ignorePaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return Returns the logCookies.
|
|
||||||
*/
|
|
||||||
public boolean getLogCookies()
|
|
||||||
{
|
|
||||||
return _logCookies;
|
|
||||||
}
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param logCookies The logCookies to set.
|
|
||||||
*/
|
|
||||||
public void setLogCookies(boolean logCookies)
|
|
||||||
{
|
|
||||||
_logCookies = logCookies;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return Returns true if logging latency
|
|
||||||
*/
|
|
||||||
public boolean getLogLatency()
|
|
||||||
{
|
|
||||||
return _logLatency;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param logLatency If true, latency is logged at the end of the log line
|
|
||||||
*/
|
|
||||||
public void setLogLatency(boolean logLatency)
|
|
||||||
{
|
|
||||||
_logLatency = logLatency;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Prefer to log the proxied-for IP address (if present in
|
|
||||||
* the request header) over the native requester IP address.
|
|
||||||
* Useful in reverse-proxy situations when you'd rather see
|
|
||||||
* the IP address of the host before the most recent proxy
|
|
||||||
* server, as opposed to your own proxy server(s) every time.
|
|
||||||
*
|
|
||||||
* jlrobins@socialserve.com, March 2004.
|
|
||||||
**/
|
|
||||||
public void setPreferProxiedForAddress(boolean value)
|
|
||||||
{
|
|
||||||
_preferProxiedForAddress = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void start()
|
|
||||||
throws Exception
|
|
||||||
{
|
|
||||||
_logDateCache=new DateCache(_logDateFormat,_logLocale);
|
|
||||||
_logDateCache.setTimeZoneID(_logTimeZone);
|
|
||||||
|
|
||||||
if (_filename != null)
|
|
||||||
{
|
|
||||||
_fileOut=new RolloverFileOutputStream(_filename,_append,_retainDays);
|
|
||||||
_closeOut=true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_fileOut=System.err;
|
|
||||||
|
|
||||||
_out=_fileOut;
|
|
||||||
|
|
||||||
if (_ignorePaths!=null && _ignorePaths.length>0)
|
|
||||||
{
|
|
||||||
_ignorePathMap=new PathMap();
|
|
||||||
for (int i=0;i<_ignorePaths.length;i++)
|
|
||||||
_ignorePathMap.put(_ignorePaths[i],_ignorePaths[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_ignorePathMap=null;
|
|
||||||
|
|
||||||
_writer=new OutputStreamWriter(_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean isStarted()
|
|
||||||
{
|
|
||||||
return _fileOut!=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void stop()
|
|
||||||
{
|
|
||||||
try{if (_writer!=null)_writer.flush();} catch (IOException e){LogSupport.ignore(log,e);}
|
|
||||||
if (_out!=null && _closeOut)
|
|
||||||
try{_out.close();}catch(IOException e){LogSupport.ignore(log,e);}
|
|
||||||
_out=null;
|
|
||||||
_fileOut=null;
|
|
||||||
_closeOut=false;
|
|
||||||
_logDateCache=null;
|
|
||||||
_writer=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Log a request.
|
|
||||||
* @param request The request
|
|
||||||
* @param response The response to this request.
|
|
||||||
* @param responseLength The bytes written to the response.
|
|
||||||
*/
|
|
||||||
public void log(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
int responseLength)
|
|
||||||
{
|
|
||||||
try{
|
|
||||||
// ignore ignorables
|
|
||||||
if (_ignorePathMap != null &&
|
|
||||||
_ignorePathMap.getMatch(request.getPath()) != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// log the rest
|
|
||||||
if (_fileOut==null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
StringBuffer buf = new StringBuffer(160);
|
|
||||||
|
|
||||||
String addr = null;
|
|
||||||
if(_preferProxiedForAddress)
|
|
||||||
{
|
|
||||||
// If header is not present, addr will remain null ...
|
|
||||||
addr = request.getField(HttpFields.__XForwardedFor);
|
|
||||||
}
|
|
||||||
if(addr == null)
|
|
||||||
addr = request.getRemoteAddr();
|
|
||||||
buf.append(addr);
|
|
||||||
|
|
||||||
buf.append(" - ");
|
|
||||||
String user = request.getAuthUser();
|
|
||||||
buf.append((user==null)?"-":user);
|
|
||||||
buf.append(" [");
|
|
||||||
buf.append(_logDateCache.format(request.getTimeStamp()));
|
|
||||||
buf.append("] \"");
|
|
||||||
buf.append(request.getMethod());
|
|
||||||
buf.append(' ');
|
|
||||||
buf.append(request.getURI());
|
|
||||||
buf.append(' ');
|
|
||||||
buf.append(request.getVersion());
|
|
||||||
buf.append("\" ");
|
|
||||||
int status=response.getStatus();
|
|
||||||
buf.append((char)('0'+((status/100)%10)));
|
|
||||||
buf.append((char)('0'+((status/10)%10)));
|
|
||||||
buf.append((char)('0'+(status%10)));
|
|
||||||
if (responseLength>=0)
|
|
||||||
{
|
|
||||||
buf.append(' ');
|
|
||||||
if (responseLength>99999)
|
|
||||||
buf.append(Integer.toString(responseLength));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (responseLength>9999)
|
|
||||||
buf.append((char)('0'+((responseLength/10000)%10)));
|
|
||||||
if (responseLength>999)
|
|
||||||
buf.append((char)('0'+((responseLength/1000)%10)));
|
|
||||||
if (responseLength>99)
|
|
||||||
buf.append((char)('0'+((responseLength/100)%10)));
|
|
||||||
if (responseLength>9)
|
|
||||||
buf.append((char)('0'+((responseLength/10)%10)));
|
|
||||||
buf.append((char)('0'+(responseLength%10)));
|
|
||||||
}
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
buf.append(" - ");
|
|
||||||
|
|
||||||
String log =buf.toString();
|
|
||||||
synchronized(_writer)
|
|
||||||
{
|
|
||||||
_writer.write(log);
|
|
||||||
if (_extended)
|
|
||||||
{
|
|
||||||
logExtended(request,response,_writer);
|
|
||||||
if (!_logCookies)
|
|
||||||
_writer.write(" -");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_logCookies)
|
|
||||||
{
|
|
||||||
Cookie[] cookies = request.getCookies();
|
|
||||||
if (cookies==null || cookies.length==0)
|
|
||||||
_writer.write(" -");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_writer.write(" \"");
|
|
||||||
for (int i=0;i<cookies.length;i++)
|
|
||||||
{
|
|
||||||
if (i!=0)
|
|
||||||
_writer.write(';');
|
|
||||||
_writer.write(cookies[i].getName());
|
|
||||||
_writer.write('=');
|
|
||||||
_writer.write(cookies[i].getValue());
|
|
||||||
}
|
|
||||||
_writer.write("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_logLatency)
|
|
||||||
_writer.write(" "+(System.currentTimeMillis()-request.getTimeStamp()));
|
|
||||||
|
|
||||||
_writer.write(StringUtil.__LINE_SEPARATOR);
|
|
||||||
_writer.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(IOException e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Log Extended fields.
|
|
||||||
* This method can be extended by a derived class to add extened fields to
|
|
||||||
* each log entry. It is called by the log method after all standard
|
|
||||||
* fields have been added, but before the line terminator.
|
|
||||||
* Derived implementations should write extra fields to the Writer
|
|
||||||
* provided.
|
|
||||||
* The default implementation writes the referer and user agent.
|
|
||||||
* @param request The request to log.
|
|
||||||
* @param response The response to log.
|
|
||||||
* @param log The writer to write the extra fields to.
|
|
||||||
* @exception IOException Problem writing log
|
|
||||||
*/
|
|
||||||
protected void logExtended(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
Writer log)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
String referer = request.getField(HttpFields.__Referer);
|
|
||||||
if(referer==null)
|
|
||||||
log.write("\"-\" ");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.write('"');
|
|
||||||
log.write(referer);
|
|
||||||
log.write("\" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
String agent = request.getField(HttpFields.__UserAgent);
|
|
||||||
if(agent==null)
|
|
||||||
log.write("\"-\"");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.write('"');
|
|
||||||
log.write(agent);
|
|
||||||
log.write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,809 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
|
||||||
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
package org.mortbay.http.handler;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.mortbay.log.LogFactory;
|
|
||||||
import org.mortbay.http.HttpException;
|
|
||||||
import org.mortbay.http.HttpFields;
|
|
||||||
import org.mortbay.http.HttpRequest;
|
|
||||||
import org.mortbay.http.HttpResponse;
|
|
||||||
import org.mortbay.http.InclusiveByteRange;
|
|
||||||
import org.mortbay.http.MultiPartResponse;
|
|
||||||
import org.mortbay.http.ResourceCache;
|
|
||||||
import org.mortbay.util.CachedResource;
|
|
||||||
import org.mortbay.util.IO;
|
|
||||||
import org.mortbay.util.LogSupport;
|
|
||||||
import org.mortbay.util.Resource;
|
|
||||||
import org.mortbay.util.StringMap;
|
|
||||||
import org.mortbay.util.TypeUtil;
|
|
||||||
import org.mortbay.util.URI;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Handler to serve files and resources.
|
|
||||||
* Serves files from a given resource URL base and implements
|
|
||||||
* the GET, HEAD, DELETE, OPTIONS, PUT, MOVE methods and the
|
|
||||||
* IfModifiedSince and IfUnmodifiedSince header fields.
|
|
||||||
* A simple memory cache is also provided to reduce file I/O.
|
|
||||||
* HTTP/1.1 ranges are supported.
|
|
||||||
*
|
|
||||||
* @version $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
|
||||||
* @author Nuno Pregui?a (sorry, wasn't UTF-8)
|
|
||||||
* @author Greg Wilkins
|
|
||||||
*/
|
|
||||||
public class ResourceHandler extends AbstractHttpHandler
|
|
||||||
{
|
|
||||||
private static Log log = LogFactory.getLog(ResourceHandler.class);
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
|
||||||
private boolean _acceptRanges=true;
|
|
||||||
private boolean _redirectWelcomeFiles ;
|
|
||||||
private String[] _methods=null;
|
|
||||||
private String _allowed;
|
|
||||||
private boolean _dirAllowed=true;
|
|
||||||
private int _minGzipLength =-1;
|
|
||||||
private StringMap _methodMap = new StringMap();
|
|
||||||
{
|
|
||||||
setAllowedMethods(new String[]
|
|
||||||
{
|
|
||||||
HttpRequest.__GET,
|
|
||||||
HttpRequest.__POST,
|
|
||||||
HttpRequest.__HEAD,
|
|
||||||
HttpRequest.__OPTIONS,
|
|
||||||
HttpRequest.__TRACE
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
|
||||||
/** Construct a ResourceHandler.
|
|
||||||
*/
|
|
||||||
public ResourceHandler()
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
|
||||||
public synchronized void start()
|
|
||||||
throws Exception
|
|
||||||
{
|
|
||||||
super.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
|
||||||
public void stop()
|
|
||||||
throws InterruptedException
|
|
||||||
{
|
|
||||||
super.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public String[] getAllowedMethods()
|
|
||||||
{
|
|
||||||
return _methods;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void setAllowedMethods(String[] methods)
|
|
||||||
{
|
|
||||||
StringBuffer b = new StringBuffer();
|
|
||||||
_methods=methods;
|
|
||||||
_methodMap.clear();
|
|
||||||
for (int i=0;i<methods.length;i++)
|
|
||||||
{
|
|
||||||
_methodMap.put(methods[i],methods[i]);
|
|
||||||
if (i>0)
|
|
||||||
b.append(',');
|
|
||||||
b.append(methods[i]);
|
|
||||||
}
|
|
||||||
_allowed=b.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean isMethodAllowed(String method)
|
|
||||||
{
|
|
||||||
return _methodMap.get(method)!=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public String getAllowedString()
|
|
||||||
{
|
|
||||||
return _allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean isDirAllowed()
|
|
||||||
{
|
|
||||||
return _dirAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void setDirAllowed(boolean dirAllowed)
|
|
||||||
{
|
|
||||||
_dirAllowed = dirAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean isAcceptRanges()
|
|
||||||
{
|
|
||||||
return _acceptRanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return True if welcome files are redirected to. False if forward is used.
|
|
||||||
*/
|
|
||||||
public boolean getRedirectWelcome()
|
|
||||||
{
|
|
||||||
return _redirectWelcomeFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param redirectWelcome True if welcome files are redirected to. False
|
|
||||||
* if forward is used.
|
|
||||||
*/
|
|
||||||
public void setRedirectWelcome(boolean redirectWelcome)
|
|
||||||
{
|
|
||||||
_redirectWelcomeFiles = redirectWelcome;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set if the handler accepts range requests.
|
|
||||||
* Default is false;
|
|
||||||
* @param ar True if the handler should accept ranges
|
|
||||||
*/
|
|
||||||
public void setAcceptRanges(boolean ar)
|
|
||||||
{
|
|
||||||
_acceptRanges=ar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get minimum content length for GZIP encoding.
|
|
||||||
* @return Minimum length of content for gzip encoding or -1 if disabled.
|
|
||||||
*/
|
|
||||||
public int getMinGzipLength()
|
|
||||||
{
|
|
||||||
return _minGzipLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set minimum content length for GZIP encoding.
|
|
||||||
* @param minGzipLength If set to a positive integer, then static content
|
|
||||||
* larger than this will be served as gzip content encoded
|
|
||||||
* if a matching resource is found ending with ".gz"
|
|
||||||
*/
|
|
||||||
public void setMinGzipLength(int minGzipLength)
|
|
||||||
{
|
|
||||||
_minGzipLength = minGzipLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** get Resource to serve.
|
|
||||||
* Map a path to a resource. The default implementation calls
|
|
||||||
* HttpContext.getResource but derived handers may provide
|
|
||||||
* their own mapping.
|
|
||||||
* @param pathInContext The path to find a resource for.
|
|
||||||
* @return The resource to serve.
|
|
||||||
*/
|
|
||||||
protected Resource getResource(String pathInContext)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return getHttpContext().getResource(pathInContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void handle(String pathInContext,
|
|
||||||
String pathParams,
|
|
||||||
HttpRequest request,
|
|
||||||
HttpResponse response)
|
|
||||||
throws HttpException, IOException
|
|
||||||
{
|
|
||||||
Resource resource = getResource(pathInContext);
|
|
||||||
if (resource==null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Is the method allowed?
|
|
||||||
if (!isMethodAllowed(request.getMethod()))
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("Method not allowed: "+request.getMethod());
|
|
||||||
if (resource.exists())
|
|
||||||
{
|
|
||||||
setAllowHeader(response);
|
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the request
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("PATH="+pathInContext+" RESOURCE="+resource);
|
|
||||||
|
|
||||||
// check filename
|
|
||||||
String method=request.getMethod();
|
|
||||||
if (method.equals(HttpRequest.__GET) ||
|
|
||||||
method.equals(HttpRequest.__POST) ||
|
|
||||||
method.equals(HttpRequest.__HEAD))
|
|
||||||
handleGet(request, response, pathInContext, pathParams, resource);
|
|
||||||
else if (method.equals(HttpRequest.__PUT))
|
|
||||||
handlePut(request, response, pathInContext, resource);
|
|
||||||
else if (method.equals(HttpRequest.__DELETE))
|
|
||||||
handleDelete(request, response, pathInContext, resource);
|
|
||||||
else if (method.equals(HttpRequest.__OPTIONS))
|
|
||||||
handleOptions(response, pathInContext);
|
|
||||||
else if (method.equals(HttpRequest.__MOVE))
|
|
||||||
handleMove(request, response, pathInContext, resource);
|
|
||||||
else if (method.equals(HttpRequest.__TRACE))
|
|
||||||
handleTrace(request, response);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("Unknown action:"+method);
|
|
||||||
// anything else...
|
|
||||||
try{
|
|
||||||
if (resource.exists())
|
|
||||||
response.sendError(HttpResponse.__501_Not_Implemented);
|
|
||||||
}
|
|
||||||
catch(Exception e) {LogSupport.ignore(log,e);}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
LogSupport.ignore(log,e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (resource!=null && !(resource instanceof CachedResource))
|
|
||||||
resource.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
|
||||||
public void handleGet(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
String pathInContext,
|
|
||||||
String pathParams,
|
|
||||||
Resource resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("Looking for "+resource);
|
|
||||||
|
|
||||||
if (resource!=null && resource.exists())
|
|
||||||
{
|
|
||||||
// check if directory
|
|
||||||
if (resource.isDirectory())
|
|
||||||
{
|
|
||||||
if (!pathInContext.endsWith("/") && !pathInContext.equals("/"))
|
|
||||||
{
|
|
||||||
log.debug("Redirect to directory/");
|
|
||||||
|
|
||||||
String q=request.getQuery();
|
|
||||||
|
|
||||||
// Properly fix URI
|
|
||||||
URI urifix = new URI(request.getRequestURL().toString());
|
|
||||||
urifix.setPath(urifix.getPath());
|
|
||||||
StringBuffer buf = new StringBuffer(urifix.toString());
|
|
||||||
urifix = null;
|
|
||||||
|
|
||||||
if (q!=null&&q.length()!=0)
|
|
||||||
{
|
|
||||||
buf.append('?');
|
|
||||||
buf.append(q);
|
|
||||||
}
|
|
||||||
response.setField(HttpFields.__Location, URI.addPaths(buf.toString(),"/"));
|
|
||||||
response.setStatus(302);
|
|
||||||
request.setHandled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if index file exists
|
|
||||||
String welcome=getHttpContext().getWelcomeFile(resource);
|
|
||||||
if (welcome!=null)
|
|
||||||
{
|
|
||||||
// Forward to the index
|
|
||||||
String ipath=URI.addPaths(pathInContext,welcome);
|
|
||||||
if (_redirectWelcomeFiles)
|
|
||||||
{
|
|
||||||
// Redirect to the index
|
|
||||||
ipath=URI.addPaths(getHttpContext().getContextPath(),ipath);
|
|
||||||
response.setContentLength(0);
|
|
||||||
response.sendRedirect(ipath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
URI uri=request.getURI();
|
|
||||||
uri.setPath(URI.addPaths(uri.getPath(),welcome));
|
|
||||||
getHttpContext().handle(ipath,pathParams,request,response);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check modified dates
|
|
||||||
if (!passConditionalHeaders(request,response,resource))
|
|
||||||
return;
|
|
||||||
// If we got here, no forward to index took place
|
|
||||||
sendDirectory(request,response,resource,pathInContext.length()>1);
|
|
||||||
}
|
|
||||||
// check if it is a file
|
|
||||||
else if (resource.exists())
|
|
||||||
{
|
|
||||||
// Check modified dates
|
|
||||||
if (!passConditionalHeaders(request,response,resource))
|
|
||||||
return;
|
|
||||||
sendData(request,response,pathInContext,resource,true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// don't know what it is
|
|
||||||
log.warn("Unknown file type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* Check modification date headers.
|
|
||||||
*/
|
|
||||||
private boolean passConditionalHeaders(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
Resource resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (!request.getMethod().equals(HttpRequest.__HEAD))
|
|
||||||
{
|
|
||||||
// If we have meta data for the file
|
|
||||||
// Try a direct match for most common requests. Avoids
|
|
||||||
// parsing the date.
|
|
||||||
ResourceCache.ResourceMetaData metaData =
|
|
||||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
|
||||||
if (metaData!=null)
|
|
||||||
{
|
|
||||||
String ifms=request.getField(HttpFields.__IfModifiedSince);
|
|
||||||
String mdlm=metaData.getLastModified();
|
|
||||||
if (ifms!=null && mdlm!=null && ifms.equals(mdlm))
|
|
||||||
{
|
|
||||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
|
||||||
request.setHandled(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
long date=0;
|
|
||||||
// Parse the if[un]modified dates and compare to resource
|
|
||||||
|
|
||||||
if ((date=request.getDateField(HttpFields.__IfUnmodifiedSince))>0)
|
|
||||||
{
|
|
||||||
if (resource.lastModified()/1000 > date/1000)
|
|
||||||
{
|
|
||||||
response.sendError(HttpResponse.__412_Precondition_Failed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((date=request.getDateField(HttpFields.__IfModifiedSince))>0)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (resource.lastModified()/1000 <= date/1000)
|
|
||||||
{
|
|
||||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
|
||||||
request.setHandled(true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
void handlePut(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
String pathInContext,
|
|
||||||
Resource resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("PUT "+pathInContext+" in "+resource);
|
|
||||||
|
|
||||||
boolean exists=resource!=null && resource.exists();
|
|
||||||
if (exists &&
|
|
||||||
!passConditionalHeaders(request,response,resource))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pathInContext.endsWith("/"))
|
|
||||||
{
|
|
||||||
if (!exists)
|
|
||||||
{
|
|
||||||
if (!resource.getFile().mkdirs())
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden, "Directories could not be created");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request.setHandled(true);
|
|
||||||
response.setStatus(HttpResponse.__201_Created);
|
|
||||||
response.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request.setHandled(true);
|
|
||||||
response.setStatus(HttpResponse.__200_OK);
|
|
||||||
response.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int toRead = request.getContentLength();
|
|
||||||
InputStream in = request.getInputStream();
|
|
||||||
OutputStream out = resource.getOutputStream();
|
|
||||||
if (toRead>=0)
|
|
||||||
IO.copy(in,out,toRead);
|
|
||||||
else
|
|
||||||
IO.copy(in,out);
|
|
||||||
out.close();
|
|
||||||
request.setHandled(true);
|
|
||||||
response.setStatus(exists
|
|
||||||
?HttpResponse.__200_OK
|
|
||||||
:HttpResponse.__201_Created);
|
|
||||||
response.commit();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,ex);
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden,
|
|
||||||
ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
void handleDelete(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
String pathInContext,
|
|
||||||
Resource resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("DELETE "+pathInContext+" from "+resource);
|
|
||||||
|
|
||||||
if (!resource.exists() ||
|
|
||||||
!passConditionalHeaders(request,response,resource))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// delete the file
|
|
||||||
if (resource.delete())
|
|
||||||
response.setStatus(HttpResponse.__204_No_Content);
|
|
||||||
else
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden);
|
|
||||||
|
|
||||||
// Send response
|
|
||||||
request.setHandled(true);
|
|
||||||
}
|
|
||||||
catch (SecurityException sex)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,sex);
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden, sex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
void handleMove(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
String pathInContext,
|
|
||||||
Resource resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (!resource.exists() || !passConditionalHeaders(request,response,resource))
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
String newPath = URI.canonicalPath(request.getField("New-uri"));
|
|
||||||
if (newPath==null)
|
|
||||||
{
|
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
|
||||||
"Bad new uri");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String contextPath = getHttpContext().getContextPath();
|
|
||||||
if (contextPath!=null && !newPath.startsWith(contextPath))
|
|
||||||
{
|
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
|
||||||
"Not in context");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Find path
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// TODO - Check this
|
|
||||||
String newInfo=newPath;
|
|
||||||
if (contextPath!=null)
|
|
||||||
newInfo=newInfo.substring(contextPath.length());
|
|
||||||
Resource newFile = getHttpContext().getBaseResource().addPath(newInfo);
|
|
||||||
|
|
||||||
if(log.isDebugEnabled())log.debug("Moving "+resource+" to "+newFile);
|
|
||||||
resource.renameTo(newFile);
|
|
||||||
|
|
||||||
response.setStatus(HttpResponse.__204_No_Content);
|
|
||||||
request.setHandled(true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,ex);
|
|
||||||
setAllowHeader(response);
|
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
|
||||||
"Error:"+ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
void handleOptions(HttpResponse response, String pathInContext)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if ("*".equals(pathInContext))
|
|
||||||
return;
|
|
||||||
setAllowHeader(response);
|
|
||||||
response.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
void setAllowHeader(HttpResponse response)
|
|
||||||
{
|
|
||||||
response.setField(HttpFields.__Allow, getAllowedString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void writeHeaders(HttpResponse response,Resource resource, long count)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ResourceCache.ResourceMetaData metaData =
|
|
||||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
|
||||||
|
|
||||||
response.setContentType(metaData.getMimeType());
|
|
||||||
if (count != -1)
|
|
||||||
{
|
|
||||||
if (count==resource.length())
|
|
||||||
response.setField(HttpFields.__ContentLength,metaData.getLength());
|
|
||||||
else
|
|
||||||
response.setContentLength((int)count);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.setField(HttpFields.__LastModified,metaData.getLastModified());
|
|
||||||
|
|
||||||
if (_acceptRanges && response.getHttpRequest().getDotVersion()>0)
|
|
||||||
response.setField(HttpFields.__AcceptRanges,"bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void sendData(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
String pathInContext,
|
|
||||||
Resource resource,
|
|
||||||
boolean writeHeaders)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
long resLength=resource.length();
|
|
||||||
|
|
||||||
// see if there are any range headers
|
|
||||||
Enumeration reqRanges =
|
|
||||||
request.getDotVersion()>0
|
|
||||||
?request.getFieldValues(HttpFields.__Range)
|
|
||||||
:null;
|
|
||||||
|
|
||||||
if (!writeHeaders || reqRanges == null || !reqRanges.hasMoreElements())
|
|
||||||
{
|
|
||||||
// look for a gziped content.
|
|
||||||
Resource data=resource;
|
|
||||||
if (_minGzipLength>0)
|
|
||||||
{
|
|
||||||
String accept=request.getField(HttpFields.__AcceptEncoding);
|
|
||||||
if (accept!=null && resLength>_minGzipLength &&
|
|
||||||
!pathInContext.endsWith(".gz"))
|
|
||||||
{
|
|
||||||
Resource gz = getHttpContext().getResource(pathInContext+".gz");
|
|
||||||
if (gz.exists() && accept.indexOf("gzip")>=0)
|
|
||||||
{
|
|
||||||
if(log.isDebugEnabled())log.debug("gzip="+gz);
|
|
||||||
response.setField(HttpFields.__ContentEncoding,"gzip");
|
|
||||||
data=gz;
|
|
||||||
resLength=data.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeHeaders(response,resource,resLength);
|
|
||||||
|
|
||||||
request.setHandled(true);
|
|
||||||
OutputStream out = response.getOutputStream();
|
|
||||||
data.writeTo(out,0,resLength);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the satisfiable ranges
|
|
||||||
List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,resLength);
|
|
||||||
if(log.isDebugEnabled())log.debug("ranges: " + reqRanges + " == " + ranges);
|
|
||||||
|
|
||||||
// if there are no satisfiable ranges, send 416 response
|
|
||||||
if (ranges==null || ranges.size()==0)
|
|
||||||
{
|
|
||||||
log.debug("no satisfiable ranges");
|
|
||||||
writeHeaders(response, resource, resLength);
|
|
||||||
response.setStatus(HttpResponse.__416_Requested_Range_Not_Satisfiable);
|
|
||||||
response.setReason((String)HttpResponse.__statusMsg
|
|
||||||
.get(TypeUtil.newInteger(HttpResponse.__416_Requested_Range_Not_Satisfiable)));
|
|
||||||
|
|
||||||
response.setField(HttpFields.__ContentRange,
|
|
||||||
InclusiveByteRange.to416HeaderRangeString(resLength));
|
|
||||||
|
|
||||||
OutputStream out = response.getOutputStream();
|
|
||||||
resource.writeTo(out,0,resLength);
|
|
||||||
request.setHandled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if there is only a single valid range (must be satisfiable
|
|
||||||
// since were here now), send that range with a 216 response
|
|
||||||
if ( ranges.size()== 1)
|
|
||||||
{
|
|
||||||
InclusiveByteRange singleSatisfiableRange =
|
|
||||||
(InclusiveByteRange)ranges.get(0);
|
|
||||||
if(log.isDebugEnabled())log.debug("single satisfiable range: " + singleSatisfiableRange);
|
|
||||||
long singleLength = singleSatisfiableRange.getSize(resLength);
|
|
||||||
writeHeaders(response,resource,singleLength);
|
|
||||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
|
||||||
response.setReason((String)HttpResponse.__statusMsg
|
|
||||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
|
||||||
response.setField(HttpFields.__ContentRange,
|
|
||||||
singleSatisfiableRange.toHeaderRangeString(resLength));
|
|
||||||
OutputStream out = response.getOutputStream();
|
|
||||||
resource.writeTo(out,
|
|
||||||
singleSatisfiableRange.getFirst(resLength),
|
|
||||||
singleLength);
|
|
||||||
request.setHandled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// multiple non-overlapping valid ranges cause a multipart
|
|
||||||
// 216 response which does not require an overall
|
|
||||||
// content-length header
|
|
||||||
//
|
|
||||||
ResourceCache.ResourceMetaData metaData =
|
|
||||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
|
||||||
String encoding = metaData.getMimeType();
|
|
||||||
MultiPartResponse multi = new MultiPartResponse(response);
|
|
||||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
|
||||||
response.setReason((String)HttpResponse.__statusMsg
|
|
||||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
|
||||||
|
|
||||||
// If the request has a "Request-Range" header then we need to
|
|
||||||
// send an old style multipart/x-byteranges Content-Type. This
|
|
||||||
// keeps Netscape and acrobat happy. This is what Apache does.
|
|
||||||
String ctp;
|
|
||||||
if (request.containsField(HttpFields.__RequestRange))
|
|
||||||
ctp = "multipart/x-byteranges; boundary=";
|
|
||||||
else
|
|
||||||
ctp = "multipart/byteranges; boundary=";
|
|
||||||
response.setContentType(ctp+multi.getBoundary());
|
|
||||||
|
|
||||||
InputStream in=(resource instanceof CachedResource)
|
|
||||||
?null:resource.getInputStream();
|
|
||||||
OutputStream out = response.getOutputStream();
|
|
||||||
long pos=0;
|
|
||||||
|
|
||||||
for (int i=0;i<ranges.size();i++)
|
|
||||||
{
|
|
||||||
InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
|
|
||||||
String header=HttpFields.__ContentRange+": "+
|
|
||||||
ibr.toHeaderRangeString(resLength);
|
|
||||||
if(log.isDebugEnabled())log.debug("multi range: "+encoding+" "+header);
|
|
||||||
multi.startPart(encoding,new String[]{header});
|
|
||||||
|
|
||||||
long start=ibr.getFirst(resLength);
|
|
||||||
long size=ibr.getSize(resLength);
|
|
||||||
if (in!=null)
|
|
||||||
{
|
|
||||||
// Handle non cached resource
|
|
||||||
if (start<pos)
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
in=resource.getInputStream();
|
|
||||||
pos=0;
|
|
||||||
}
|
|
||||||
if (pos<start)
|
|
||||||
{
|
|
||||||
in.skip(start-pos);
|
|
||||||
pos=start;
|
|
||||||
}
|
|
||||||
IO.copy(in,out,size);
|
|
||||||
pos+=size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// Handle cached resource
|
|
||||||
resource.writeTo(out,start,size);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (in!=null)
|
|
||||||
in.close();
|
|
||||||
multi.close();
|
|
||||||
|
|
||||||
request.setHandled(true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
|
||||||
void sendDirectory(HttpRequest request,
|
|
||||||
HttpResponse response,
|
|
||||||
Resource resource,
|
|
||||||
boolean parent)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (!_dirAllowed)
|
|
||||||
{
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.setHandled(true);
|
|
||||||
|
|
||||||
if(log.isDebugEnabled())log.debug("sendDirectory: "+resource);
|
|
||||||
byte[] data=null;
|
|
||||||
if (resource instanceof CachedResource)
|
|
||||||
data=((CachedResource)resource).getCachedData();
|
|
||||||
|
|
||||||
if (data==null)
|
|
||||||
{
|
|
||||||
String base = URI.addPaths(request.getPath(),"/");
|
|
||||||
String dir = resource.getListHTML(URI.encodePath(base),parent);
|
|
||||||
if (dir==null)
|
|
||||||
{
|
|
||||||
response.sendError(HttpResponse.__403_Forbidden,
|
|
||||||
"No directory");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data=dir.getBytes("UTF8");
|
|
||||||
if (resource instanceof CachedResource)
|
|
||||||
((CachedResource)resource).setCachedData(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.setContentType("text/html; charset=UTF8");
|
|
||||||
response.setContentLength(data.length);
|
|
||||||
|
|
||||||
if (request.getMethod().equals(HttpRequest.__HEAD))
|
|
||||||
{
|
|
||||||
response.commit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
response.getOutputStream().write(data,0,data.length);
|
|
||||||
response.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,617 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: Server.java,v 1.40 2005/10/21 13:52:11 gregwilkins Exp $
|
|
||||||
// Copyright 2002-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
package org.mortbay.jetty;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.mortbay.log.LogFactory;
|
|
||||||
import org.mortbay.http.HttpContext;
|
|
||||||
import org.mortbay.http.HttpServer;
|
|
||||||
import org.mortbay.jetty.servlet.ServletHttpContext;
|
|
||||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
|
||||||
import org.mortbay.util.LogSupport;
|
|
||||||
import org.mortbay.util.Resource;
|
|
||||||
import org.mortbay.xml.XmlConfiguration;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** The Jetty HttpServer.
|
|
||||||
*
|
|
||||||
* This specialization of org.mortbay.http.HttpServer adds knowledge
|
|
||||||
* about servlets and their specialized contexts. It also included
|
|
||||||
* support for initialization from xml configuration files
|
|
||||||
* that follow the XmlConfiguration dtd.
|
|
||||||
*
|
|
||||||
* HttpContexts created by Server are of the type
|
|
||||||
* org.mortbay.jetty.servlet.ServletHttpContext unless otherwise
|
|
||||||
* specified.
|
|
||||||
*
|
|
||||||
* This class also provides a main() method which starts a server for
|
|
||||||
* each config file passed on the command line. If the system
|
|
||||||
* property JETTY_NO_SHUTDOWN_HOOK is not set to true, then a shutdown
|
|
||||||
* hook is thread is registered to stop these servers.
|
|
||||||
*
|
|
||||||
* @see org.mortbay.xml.XmlConfiguration
|
|
||||||
* @see org.mortbay.jetty.servlet.ServletHttpContext
|
|
||||||
* @version $Revision: 1.40 $
|
|
||||||
* @author Greg Wilkins (gregw)
|
|
||||||
*/
|
|
||||||
public class Server extends HttpServer
|
|
||||||
{
|
|
||||||
static Log log = LogFactory.getLog(Server.class);
|
|
||||||
private String[] _webAppConfigurationClassNames =
|
|
||||||
new String[]{"org.mortbay.jetty.servlet.XMLConfiguration", "org.mortbay.jetty.servlet.JettyWebConfiguration"};
|
|
||||||
private String _configuration;
|
|
||||||
private String _rootWebApp;
|
|
||||||
private static ShutdownHookThread hookThread = new ShutdownHookThread();
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
*/
|
|
||||||
public Server()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param configuration The filename or URL of the XML
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public Server(String configuration)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
this(Resource.newResource(configuration).getURL());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param configuration The filename or URL of the XML
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public Server(Resource configuration)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
this(configuration.getURL());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param configuration The filename or URL of the XML
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public Server(URL configuration)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
_configuration=configuration.toString();
|
|
||||||
Server.hookThread.add(this);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
XmlConfiguration config=new XmlConfiguration(configuration);
|
|
||||||
config.configure(this);
|
|
||||||
}
|
|
||||||
catch(IOException e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch(InvocationTargetException e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e.getTargetException());
|
|
||||||
throw new IOException("Jetty configuration problem: "+e.getTargetException());
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e);
|
|
||||||
throw new IOException("Jetty configuration problem: "+e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public boolean getStopAtShutdown()
|
|
||||||
{
|
|
||||||
return hookThread.contains(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void setStopAtShutdown(boolean stop)
|
|
||||||
{
|
|
||||||
if (stop)
|
|
||||||
hookThread.add(this);
|
|
||||||
else
|
|
||||||
hookThread.remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the root webapp name.
|
|
||||||
* @return The name of the root webapp (eg. "root" for root.war).
|
|
||||||
*/
|
|
||||||
public String getRootWebApp()
|
|
||||||
{
|
|
||||||
return _rootWebApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the root webapp name.
|
|
||||||
* @param rootWebApp The name of the root webapp (eg. "root" for root.war).
|
|
||||||
*/
|
|
||||||
public void setRootWebApp(String rootWebApp)
|
|
||||||
{
|
|
||||||
_rootWebApp = rootWebApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Configure the server from an XML file.
|
|
||||||
* @param configuration The filename or URL of the XML
|
|
||||||
* configuration file.
|
|
||||||
*/
|
|
||||||
public void configure(String configuration)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
|
|
||||||
URL url=Resource.newResource(configuration).getURL();
|
|
||||||
if (_configuration!=null && _configuration.equals(url.toString()))
|
|
||||||
return;
|
|
||||||
if (_configuration!=null)
|
|
||||||
throw new IllegalStateException("Already configured with "+_configuration);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
XmlConfiguration config=new XmlConfiguration(url);
|
|
||||||
_configuration=url.toString();
|
|
||||||
config.configure(this);
|
|
||||||
}
|
|
||||||
catch(IOException e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e);
|
|
||||||
throw new IOException("Jetty configuration problem: "+e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public String getConfiguration()
|
|
||||||
{
|
|
||||||
return _configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Create a new ServletHttpContext.
|
|
||||||
* Ths method is called by HttpServer to creat new contexts. Thus
|
|
||||||
* calls to addContext or getContext that result in a new Context
|
|
||||||
* being created will return an
|
|
||||||
* org.mortbay.jetty.servlet.ServletHttpContext instance.
|
|
||||||
* @return ServletHttpContext
|
|
||||||
*/
|
|
||||||
protected HttpContext newHttpContext()
|
|
||||||
{
|
|
||||||
return new ServletHttpContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Create a new WebApplicationContext.
|
|
||||||
* Ths method is called by Server to creat new contexts for web
|
|
||||||
* applications. Thus calls to addWebApplication that result in
|
|
||||||
* a new Context being created will return an correct class instance.
|
|
||||||
* Derived class can override this method to create instance of its
|
|
||||||
* own class derived from WebApplicationContext in case it needs more
|
|
||||||
* functionality.
|
|
||||||
* @param webApp The Web application directory or WAR file.
|
|
||||||
* @return WebApplicationContext
|
|
||||||
*/
|
|
||||||
protected WebApplicationContext newWebApplicationContext(
|
|
||||||
String webApp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return new WebApplicationContext(webApp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Application.
|
|
||||||
* @param contextPathSpec The context path spec. Which must be of
|
|
||||||
* the form / or /path/*
|
|
||||||
* @param webApp The Web application directory or WAR file.
|
|
||||||
* @return The WebApplicationContext
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext addWebApplication(String contextPathSpec,
|
|
||||||
String webApp)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplication(null,contextPathSpec,webApp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Application.
|
|
||||||
* @param virtualHost Virtual host name or null
|
|
||||||
* @param contextPathSpec The context path spec. Which must be of
|
|
||||||
* the form / or /path/*
|
|
||||||
* @param webApp The Web application directory or WAR file.
|
|
||||||
* @return The WebApplicationContext
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext addWebApplication(String virtualHost,
|
|
||||||
String contextPathSpec,
|
|
||||||
String webApp)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
WebApplicationContext appContext =
|
|
||||||
newWebApplicationContext(webApp);
|
|
||||||
appContext.setContextPath(contextPathSpec);
|
|
||||||
addContext(virtualHost,appContext);
|
|
||||||
if(log.isDebugEnabled())log.debug("Web Application "+appContext+" added");
|
|
||||||
return appContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If a
|
|
||||||
* webapp is called "root" it is added at "/".
|
|
||||||
* @param webapps Directory file name or URL to look for auto webapplication.
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String webapps)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplications(null,webapps,null,false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If the
|
|
||||||
* webapp matches the rootWebApp it is added as the "/" context.
|
|
||||||
* @param host Virtual host name or null
|
|
||||||
* @param webapps Directory file name or URL to look for auto webapplication.
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String host,
|
|
||||||
String webapps)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplications(host,webapps,null,false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If the
|
|
||||||
* webapp matches the rootWebApp it is added as the "/" context.
|
|
||||||
* @param host Virtual host name or null
|
|
||||||
* @param webapps Directory file name or URL to look for auto
|
|
||||||
* webapplication.
|
|
||||||
* @param extract If true, extract war files
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String host,
|
|
||||||
String webapps,
|
|
||||||
boolean extract)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplications(host,webapps,null,extract);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If the
|
|
||||||
* webapp matches the rootWebApp it is added as the "/" context.
|
|
||||||
* @param host Virtual host name or null
|
|
||||||
* @param webapps Directory file name or URL to look for auto
|
|
||||||
* webapplication.
|
|
||||||
* @param defaults The defaults xml filename or URL which is
|
|
||||||
* loaded before any in the web app. Must respect the web.dtd.
|
|
||||||
* If null the default defaults file is used. If the empty string, then
|
|
||||||
* no defaults file is used.
|
|
||||||
* @param extract If true, extract war files
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String host,
|
|
||||||
String webapps,
|
|
||||||
String defaults,
|
|
||||||
boolean extract)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplications(host,webapps,defaults,extract,true,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If the
|
|
||||||
* webapp matches the rootWebApp it is added as the "/" context.
|
|
||||||
* @param host Virtual host name or null
|
|
||||||
* @param webapps Directory file name or URL to look for auto
|
|
||||||
* webapplication.
|
|
||||||
* @param defaults The defaults xml filename or URL which is
|
|
||||||
* loaded before any in the web app. Must respect the web.dtd.
|
|
||||||
* If null the default defaults file is used. If the empty string, then
|
|
||||||
* no defaults file is used.
|
|
||||||
* @param extract If true, extract war files
|
|
||||||
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String host,
|
|
||||||
String webapps,
|
|
||||||
String defaults,
|
|
||||||
boolean extract,
|
|
||||||
boolean java2CompliantClassLoader)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return addWebApplications(host,webapps,defaults,extract,java2CompliantClassLoader,null);
|
|
||||||
|
|
||||||
}
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Add Web Applications.
|
|
||||||
* Add auto webapplications to the server. The name of the
|
|
||||||
* webapp directory or war is used as the context name. If the
|
|
||||||
* webapp matches the rootWebApp it is added as the "/" context.
|
|
||||||
* @param host Virtual host name or null
|
|
||||||
* @param webapps Directory file name or URL to look for auto
|
|
||||||
* webapplication.
|
|
||||||
* @param defaults The defaults xml filename or URL which is
|
|
||||||
* loaded before any in the web app. Must respect the web.dtd.
|
|
||||||
* If null the default defaults file is used. If the empty string, then
|
|
||||||
* no defaults file is used.
|
|
||||||
* @param extract If true, extract war files
|
|
||||||
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
|
|
||||||
* @param Attributes[] A set of attributes to pass to setAttribute, format is first item is the key, second item is the value.
|
|
||||||
* @exception IOException
|
|
||||||
*/
|
|
||||||
public WebApplicationContext[] addWebApplications(String host,
|
|
||||||
String webapps,
|
|
||||||
String defaults,
|
|
||||||
boolean extract,
|
|
||||||
boolean java2CompliantClassLoader,
|
|
||||||
String Attributes[])
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
ArrayList wacs = new ArrayList();
|
|
||||||
Resource r=Resource.newResource(webapps);
|
|
||||||
if (!r.exists())
|
|
||||||
throw new IllegalArgumentException("No such webapps resource "+r);
|
|
||||||
|
|
||||||
if (!r.isDirectory())
|
|
||||||
throw new IllegalArgumentException("Not directory webapps resource "+r);
|
|
||||||
if(Attributes != null) {
|
|
||||||
if(((Attributes.length / 2) * 2) != Attributes.length) {
|
|
||||||
throw new IllegalArgumentException("Attributes must be in pairs of key,value.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String[] files=r.list();
|
|
||||||
|
|
||||||
for (int f=0;files!=null && f<files.length;f++)
|
|
||||||
{
|
|
||||||
String context=files[f];
|
|
||||||
|
|
||||||
if (context.equalsIgnoreCase("CVS/") ||
|
|
||||||
context.equalsIgnoreCase("CVS") ||
|
|
||||||
context.startsWith("."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
|
||||||
String app = r.addPath(r.encode(files[f])).toString();
|
|
||||||
if (context.toLowerCase().endsWith(".war") ||
|
|
||||||
context.toLowerCase().endsWith(".jar"))
|
|
||||||
{
|
|
||||||
context=context.substring(0,context.length()-4);
|
|
||||||
Resource unpacked=r.addPath(context);
|
|
||||||
if (unpacked!=null && unpacked.exists() && unpacked.isDirectory())
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rootWebApp!=null && (context.equals(_rootWebApp)||context.equals(_rootWebApp+"/")))
|
|
||||||
context="/";
|
|
||||||
else
|
|
||||||
context="/"+context;
|
|
||||||
|
|
||||||
WebApplicationContext wac= addWebApplication(host,
|
|
||||||
context,
|
|
||||||
app);
|
|
||||||
wac.setExtractWAR(extract);
|
|
||||||
wac.setClassLoaderJava2Compliant(java2CompliantClassLoader);
|
|
||||||
if (defaults!=null)
|
|
||||||
{
|
|
||||||
if (defaults.length()==0)
|
|
||||||
wac.setDefaultsDescriptor(null);
|
|
||||||
else
|
|
||||||
wac.setDefaultsDescriptor(defaults);
|
|
||||||
}
|
|
||||||
if(Attributes != null) {
|
|
||||||
for(int i = 0; i < Attributes.length; i++, i++) {
|
|
||||||
wac.setAttribute(Attributes[i],Attributes[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wacs.add(wac);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (WebApplicationContext[])wacs.toArray(new WebApplicationContext[wacs.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** setWebApplicationConfigurationClasses
|
|
||||||
* Set up the list of classnames of WebApplicationContext.Configuration
|
|
||||||
* implementations that will be applied to configure every webapp.
|
|
||||||
* The list can be overridden by individual WebApplicationContexts.
|
|
||||||
* @param configurationClasses
|
|
||||||
*/
|
|
||||||
public void setWebApplicationConfigurationClassNames (String[] configurationClassNames)
|
|
||||||
{
|
|
||||||
if (configurationClassNames != null)
|
|
||||||
{
|
|
||||||
_webAppConfigurationClassNames = new String[configurationClassNames.length];
|
|
||||||
System.arraycopy(configurationClassNames, 0, _webAppConfigurationClassNames, 0, configurationClassNames.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getWebApplicationConfigurationClassNames ()
|
|
||||||
{
|
|
||||||
return _webAppConfigurationClassNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public static void main(String[] arg)
|
|
||||||
{
|
|
||||||
String[] dftConfig={"etc/jetty.xml"};
|
|
||||||
|
|
||||||
if (arg.length==0)
|
|
||||||
{
|
|
||||||
log.info("Using default configuration: etc/jetty.xml");
|
|
||||||
arg=dftConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Server[] servers=new Server[arg.length];
|
|
||||||
|
|
||||||
// create and start the servers.
|
|
||||||
for (int i=0;i<arg.length;i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
servers[i] = new Server(arg[i]);
|
|
||||||
servers[i].setStopAtShutdown(true);
|
|
||||||
servers[i].start();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create and start the servers.
|
|
||||||
for (int i=0;i<arg.length;i++)
|
|
||||||
{
|
|
||||||
try{servers[i].join();}
|
|
||||||
catch (Exception e){LogSupport.ignore(log,e);}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ShutdownHook thread for stopping all servers.
|
|
||||||
*
|
|
||||||
* Thread is hooked first time list of servers is changed.
|
|
||||||
*/
|
|
||||||
private static class ShutdownHookThread extends Thread {
|
|
||||||
private boolean hooked = false;
|
|
||||||
private ArrayList servers = new ArrayList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hooks this thread for shutdown.
|
|
||||||
* @see java.lang.Runtime#addShutdownHook(java.lang.Thread)
|
|
||||||
*/
|
|
||||||
private void createShutdownHook() {
|
|
||||||
if (!Boolean.getBoolean("JETTY_NO_SHUTDOWN_HOOK") && !hooked) {
|
|
||||||
try {
|
|
||||||
Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook",
|
|
||||||
new Class[] { java.lang.Thread.class });
|
|
||||||
shutdownHook.invoke(Runtime.getRuntime(), new Object[] { this });
|
|
||||||
this.hooked = true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (log.isDebugEnabled()) log.debug("No shutdown hook in JVM ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add Server to servers list.
|
|
||||||
*/
|
|
||||||
public boolean add(Server server) {
|
|
||||||
createShutdownHook();
|
|
||||||
return this.servers.add(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains Server in servers list?
|
|
||||||
*/
|
|
||||||
public boolean contains(Server server) {
|
|
||||||
return this.servers.contains(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append all Servers from Collection
|
|
||||||
*/
|
|
||||||
public boolean addAll(Collection c) {
|
|
||||||
createShutdownHook();
|
|
||||||
return this.servers.addAll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear list of Servers.
|
|
||||||
*/
|
|
||||||
public void clear() {
|
|
||||||
createShutdownHook();
|
|
||||||
this.servers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove Server from list.
|
|
||||||
*/
|
|
||||||
public boolean remove(Server server) {
|
|
||||||
createShutdownHook();
|
|
||||||
return this.servers.remove(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all Servers in Collection from list.
|
|
||||||
*/
|
|
||||||
public boolean removeAll(Collection c) {
|
|
||||||
createShutdownHook();
|
|
||||||
return this.servers.removeAll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop all Servers in list.
|
|
||||||
*/
|
|
||||||
public void run() {
|
|
||||||
setName("Shutdown");
|
|
||||||
log.info("Shutdown hook executing");
|
|
||||||
Iterator it = servers.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Server svr = (Server) it.next();
|
|
||||||
if (svr == null) continue;
|
|
||||||
try {
|
|
||||||
svr.stop();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn(LogSupport.EXCEPTION, e);
|
|
||||||
}
|
|
||||||
log.info("Shutdown hook complete");
|
|
||||||
|
|
||||||
// Try to avoid JVM crash
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn(LogSupport.EXCEPTION, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,352 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: FileResource.java,v 1.31 2006/01/04 13:55:31 gregwilkins Exp $
|
|
||||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
package org.mortbay.util;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.security.Permission;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.mortbay.log.LogFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** File Resource.
|
|
||||||
*
|
|
||||||
* Handle resources of implied or explicit file type.
|
|
||||||
* This class can check for aliasing in the filesystem (eg case
|
|
||||||
* insensitivity). By default this is turned on if the platform does
|
|
||||||
* not have the "/" path separator, or it can be controlled with the
|
|
||||||
* "org.mortbay.util.FileResource.checkAliases" system parameter.
|
|
||||||
*
|
|
||||||
* If alias checking is turned on, then aliased resources are
|
|
||||||
* treated as if they do not exist, nor can they be created.
|
|
||||||
*
|
|
||||||
* @version $Revision: 1.31 $
|
|
||||||
* @author Greg Wilkins (gregw)
|
|
||||||
*/
|
|
||||||
public class FileResource extends URLResource
|
|
||||||
{
|
|
||||||
private static Log log = LogFactory.getLog(Credential.class);
|
|
||||||
private static boolean __checkAliases;
|
|
||||||
static
|
|
||||||
{
|
|
||||||
__checkAliases=
|
|
||||||
"true".equalsIgnoreCase
|
|
||||||
(System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
|
|
||||||
|
|
||||||
if (__checkAliases)
|
|
||||||
log.info("Checking Resource aliases");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private File _file;
|
|
||||||
private transient URL _alias=null;
|
|
||||||
private transient boolean _aliasChecked=false;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
|
||||||
/** setCheckAliases.
|
|
||||||
* @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
|
||||||
*/
|
|
||||||
public static void setCheckAliases(boolean checkAliases)
|
|
||||||
{
|
|
||||||
__checkAliases=checkAliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
|
||||||
/** getCheckAliases.
|
|
||||||
* @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
|
||||||
*/
|
|
||||||
public static boolean getCheckAliases()
|
|
||||||
{
|
|
||||||
return __checkAliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
FileResource(URL url)
|
|
||||||
throws IOException, URISyntaxException
|
|
||||||
{
|
|
||||||
super(url,null);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Try standard API to convert URL to file.
|
|
||||||
_file =new File(new URI(url.toString()));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
LogSupport.ignore(log,e);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Assume that File.toURL produced unencoded chars. So try
|
|
||||||
// encoding them.
|
|
||||||
String urls=
|
|
||||||
"file:"+org.mortbay.util.URI.encodePath(url.toString().substring(5));
|
|
||||||
_file =new File(new URI(urls));
|
|
||||||
}
|
|
||||||
catch (Exception e2)
|
|
||||||
{
|
|
||||||
LogSupport.ignore(log,e2);
|
|
||||||
|
|
||||||
// Still can't get the file. Doh! try good old hack!
|
|
||||||
checkConnection();
|
|
||||||
Permission perm = _connection.getPermission();
|
|
||||||
_file = new File(perm==null?url.getFile():perm.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
|
||||||
_urlString=_urlString+"/";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
FileResource(URL url, URLConnection connection, File file)
|
|
||||||
{
|
|
||||||
super(url,connection);
|
|
||||||
_file=file;
|
|
||||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
|
||||||
_urlString=_urlString+"/";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
public Resource addPath(String path)
|
|
||||||
throws IOException,MalformedURLException
|
|
||||||
{
|
|
||||||
FileResource r=null;
|
|
||||||
|
|
||||||
if (!isDirectory())
|
|
||||||
{
|
|
||||||
r=(FileResource)super.addPath(path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
path = org.mortbay.util.URI.canonicalPath(path);
|
|
||||||
|
|
||||||
// treat all paths being added as relative
|
|
||||||
String rel=path;
|
|
||||||
if (path.startsWith("/"))
|
|
||||||
rel = path.substring(1);
|
|
||||||
|
|
||||||
File newFile = new File(_file,rel.replace('/', File.separatorChar));
|
|
||||||
r=new FileResource(newFile.toURI().toURL(),null,newFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
String encoded=org.mortbay.util.URI.encodePath(path);
|
|
||||||
int expected=r._urlString.length()-encoded.length();
|
|
||||||
int index = r._urlString.lastIndexOf(encoded, expected);
|
|
||||||
|
|
||||||
if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
|
|
||||||
{
|
|
||||||
r._alias=r._url;
|
|
||||||
r._aliasChecked=true;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public URL getAlias()
|
|
||||||
{
|
|
||||||
if (__checkAliases) {
|
|
||||||
if (!_aliasChecked)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String abs=_file.getAbsolutePath();
|
|
||||||
String can=_file.getCanonicalPath();
|
|
||||||
|
|
||||||
if (abs.length()!=can.length() || !abs.equals(can))
|
|
||||||
_alias=new File(can).toURI().toURL();
|
|
||||||
|
|
||||||
_aliasChecked=true;
|
|
||||||
|
|
||||||
if (_alias!=null && log.isDebugEnabled())
|
|
||||||
{
|
|
||||||
log.debug("ALIAS abs="+abs);
|
|
||||||
log.debug("ALIAS can="+can);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
log.warn(LogSupport.EXCEPTION,e);
|
|
||||||
return getURL();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else return null;
|
|
||||||
return _alias;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns true if the resource exists.
|
|
||||||
*/
|
|
||||||
public boolean exists()
|
|
||||||
{
|
|
||||||
return _file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns the last modified time
|
|
||||||
*/
|
|
||||||
public long lastModified()
|
|
||||||
{
|
|
||||||
return _file.lastModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns true if the respresenetd resource is a container/directory.
|
|
||||||
*/
|
|
||||||
public boolean isDirectory()
|
|
||||||
{
|
|
||||||
return _file.isDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Return the length of the resource
|
|
||||||
*/
|
|
||||||
public long length()
|
|
||||||
{
|
|
||||||
return _file.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns the name of the resource
|
|
||||||
*/
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns an File representing the given resource or NULL if this
|
|
||||||
* is not possible.
|
|
||||||
*/
|
|
||||||
public File getFile()
|
|
||||||
{
|
|
||||||
return _file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns an input stream to the resource
|
|
||||||
*/
|
|
||||||
public InputStream getInputStream() throws IOException
|
|
||||||
{
|
|
||||||
return new FileInputStream(_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns an output stream to the resource
|
|
||||||
*/
|
|
||||||
public OutputStream getOutputStream()
|
|
||||||
throws java.io.IOException, SecurityException
|
|
||||||
{
|
|
||||||
return new FileOutputStream(_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Deletes the given resource
|
|
||||||
*/
|
|
||||||
public boolean delete()
|
|
||||||
throws SecurityException
|
|
||||||
{
|
|
||||||
return _file.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Rename the given resource
|
|
||||||
*/
|
|
||||||
public boolean renameTo( Resource dest)
|
|
||||||
throws SecurityException
|
|
||||||
{
|
|
||||||
if( dest instanceof FileResource)
|
|
||||||
return _file.renameTo( ((FileResource)dest)._file);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Returns a list of resources contained in the given resource
|
|
||||||
*/
|
|
||||||
public String[] list()
|
|
||||||
{
|
|
||||||
String[] list =_file.list();
|
|
||||||
if (list==null)
|
|
||||||
return null;
|
|
||||||
for (int i=list.length;i-->0;)
|
|
||||||
{
|
|
||||||
if (new File(_file,list[i]).isDirectory() &&
|
|
||||||
!list[i].endsWith("/"))
|
|
||||||
list[i]+="/";
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Encode according to this resource type.
|
|
||||||
* File URIs are encoded.
|
|
||||||
* @param uri URI to encode.
|
|
||||||
* @return The uri unchanged.
|
|
||||||
*/
|
|
||||||
public String encode(String uri)
|
|
||||||
{
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param o
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean equals( Object o)
|
|
||||||
{
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (null == o || ! (o instanceof FileResource))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FileResource f=(FileResource)o;
|
|
||||||
return f._file == _file || (null != _file && _file.equals(f._file));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return the hashcode.
|
|
||||||
*/
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return null == _file ? super.hashCode() : _file.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,253 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: InetAddrPort.java,v 1.7 2004/10/23 09:03:22 gregwilkins Exp $
|
|
||||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
package org.mortbay.util;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
/* ======================================================================== */
|
|
||||||
/** InetAddress and Port.
|
|
||||||
*/
|
|
||||||
public class InetAddrPort implements Serializable
|
|
||||||
{
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public final static String __0_0_0_0 = "0.0.0.0";
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
private InetAddress _addr=null;
|
|
||||||
private boolean _addrIsHost=false;
|
|
||||||
private int _port=0;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
|
||||||
public InetAddrPort()
|
|
||||||
{}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor for a port on all local host address.
|
|
||||||
* @param port
|
|
||||||
*/
|
|
||||||
public InetAddrPort(int port)
|
|
||||||
{
|
|
||||||
_port=port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param addr
|
|
||||||
* @param port
|
|
||||||
*/
|
|
||||||
public InetAddrPort(InetAddress addr, int port)
|
|
||||||
{
|
|
||||||
_addr=addr;
|
|
||||||
_port=port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param host
|
|
||||||
* @param port
|
|
||||||
*/
|
|
||||||
public InetAddrPort(String host, int port)
|
|
||||||
throws java.net.UnknownHostException
|
|
||||||
{
|
|
||||||
setHost(host);
|
|
||||||
setPort(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* Patched to support [::1]:port for I2P
|
|
||||||
*
|
|
||||||
* @param inetAddrPort String of the form "addr:port"
|
|
||||||
*/
|
|
||||||
public InetAddrPort(String inetAddrPort)
|
|
||||||
throws java.net.UnknownHostException
|
|
||||||
{
|
|
||||||
int b = inetAddrPort.indexOf('[');
|
|
||||||
if (b>0)
|
|
||||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
|
||||||
if (b==0) // IPV6
|
|
||||||
{
|
|
||||||
int b2 = inetAddrPort.indexOf(']');
|
|
||||||
if (b2<2)
|
|
||||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
|
||||||
String addr=inetAddrPort.substring(1,b2);
|
|
||||||
if (addr.indexOf('/')>0)
|
|
||||||
addr=addr.substring(addr.indexOf('/')+1);
|
|
||||||
inetAddrPort=inetAddrPort.substring(b2+1);
|
|
||||||
int c = inetAddrPort.indexOf(':');
|
|
||||||
if (c>0)
|
|
||||||
throw new java.net.UnknownHostException("Bad [] syntax");
|
|
||||||
if (c==0)
|
|
||||||
inetAddrPort=inetAddrPort.substring(1);
|
|
||||||
|
|
||||||
if (addr.length()>0 && ! __0_0_0_0.equals(addr))
|
|
||||||
{
|
|
||||||
_addrIsHost=!Character.isDigit((addr.charAt(0)));
|
|
||||||
this._addr=InetAddress.getByName(addr);
|
|
||||||
}
|
|
||||||
} else { // IPV4
|
|
||||||
int c = inetAddrPort.indexOf(':');
|
|
||||||
if (c>=0)
|
|
||||||
{
|
|
||||||
String addr=inetAddrPort.substring(0,c);
|
|
||||||
if (addr.indexOf('/')>0)
|
|
||||||
addr=addr.substring(addr.indexOf('/')+1);
|
|
||||||
inetAddrPort=inetAddrPort.substring(c+1);
|
|
||||||
|
|
||||||
if (addr.length()>0 && ! __0_0_0_0.equals(addr))
|
|
||||||
{
|
|
||||||
_addrIsHost=!Character.isDigit((addr.charAt(0)));
|
|
||||||
this._addr=InetAddress.getByName(addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_port = Integer.parseInt(inetAddrPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Constructor.
|
|
||||||
* @param address InetAddrPort top copy.
|
|
||||||
*/
|
|
||||||
public InetAddrPort(InetAddrPort address)
|
|
||||||
{
|
|
||||||
if (address!=null)
|
|
||||||
{
|
|
||||||
_addr=address._addr;
|
|
||||||
_port=address._port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the Host.
|
|
||||||
* @return The IP address
|
|
||||||
*/
|
|
||||||
public String getHost()
|
|
||||||
{
|
|
||||||
if (_addr==null)
|
|
||||||
return __0_0_0_0;
|
|
||||||
|
|
||||||
return _addrIsHost?_addr.getHostName():_addr.getHostAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the Host.
|
|
||||||
* @param host
|
|
||||||
* @exception java.net.UnknownHostException
|
|
||||||
*/
|
|
||||||
public void setHost(String host)
|
|
||||||
throws java.net.UnknownHostException
|
|
||||||
{
|
|
||||||
_addr=null;
|
|
||||||
if (host!=null)
|
|
||||||
{
|
|
||||||
if (host.indexOf('/')>0)
|
|
||||||
host=host.substring(0,host.indexOf('/'));
|
|
||||||
_addrIsHost=!Character.isDigit((host.charAt(0)));
|
|
||||||
_addr=InetAddress.getByName(host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the IP address.
|
|
||||||
* @return The IP address
|
|
||||||
*/
|
|
||||||
public InetAddress getInetAddress()
|
|
||||||
{
|
|
||||||
return _addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the IP address.
|
|
||||||
* @param addr The IP address
|
|
||||||
*/
|
|
||||||
public void setInetAddress(InetAddress addr)
|
|
||||||
{
|
|
||||||
_addrIsHost=false;
|
|
||||||
_addr=addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the port.
|
|
||||||
* @return The port number
|
|
||||||
*/
|
|
||||||
public int getPort()
|
|
||||||
{
|
|
||||||
return _port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Set the port.
|
|
||||||
* @param port The port number
|
|
||||||
*/
|
|
||||||
public void setPort(int port)
|
|
||||||
{
|
|
||||||
_port=port;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------- */
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return getHost()+':'+_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Clone the InetAddrPort.
|
|
||||||
* @return A new instance.
|
|
||||||
*/
|
|
||||||
public Object clone()
|
|
||||||
{
|
|
||||||
return new InetAddrPort(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Hash Code.
|
|
||||||
* @return hash Code.
|
|
||||||
*/
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return _port+((_addr==null)?0:_addr.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Equals.
|
|
||||||
* @param o
|
|
||||||
* @return True if is the same address and port.
|
|
||||||
*/
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
if (o==null)
|
|
||||||
return false;
|
|
||||||
if (o==this)
|
|
||||||
return true;
|
|
||||||
if (o instanceof InetAddrPort)
|
|
||||||
{
|
|
||||||
InetAddrPort addr=(InetAddrPort)o;
|
|
||||||
return addr._port==_port &&
|
|
||||||
( addr._addr==_addr ||
|
|
||||||
addr._addr!=null && addr._addr.equals(_addr));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,431 +0,0 @@
|
|||||||
// ========================================================================
|
|
||||||
// $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $
|
|
||||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
// ========================================================================
|
|
||||||
package org.mortbay.util;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.mortbay.log.LogFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Abstract resource class.
|
|
||||||
*
|
|
||||||
* @version $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $
|
|
||||||
* @author Nuno Preguica
|
|
||||||
* @author Greg Wilkins (gregw)
|
|
||||||
*/
|
|
||||||
public abstract class Resource implements Serializable
|
|
||||||
{
|
|
||||||
private static Log log = LogFactory.getLog(Resource.class);
|
|
||||||
|
|
||||||
Object _associate;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Construct a resource from a url.
|
|
||||||
* @param url A URL.
|
|
||||||
* @return A Resource object.
|
|
||||||
*/
|
|
||||||
public static Resource newResource(URL url)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (url==null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
String urls=url.toExternalForm();
|
|
||||||
if( urls.startsWith( "file:"))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FileResource fileResource= new FileResource(url);
|
|
||||||
return fileResource;
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
log.debug(LogSupport.EXCEPTION,e);
|
|
||||||
return new BadResource(url,e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( urls.startsWith( "jar:file:"))
|
|
||||||
{
|
|
||||||
return new JarFileResource(url);
|
|
||||||
}
|
|
||||||
else if( urls.startsWith( "jar:"))
|
|
||||||
{
|
|
||||||
return new JarResource(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new URLResource(url,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Construct a resource from a string.
|
|
||||||
* @param resource A URL or filename.
|
|
||||||
* @return A Resource object.
|
|
||||||
*/
|
|
||||||
public static Resource newResource(String resource)
|
|
||||||
throws MalformedURLException, IOException
|
|
||||||
{
|
|
||||||
URL url=null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Try to format as a URL?
|
|
||||||
url = new URL(resource);
|
|
||||||
}
|
|
||||||
catch(MalformedURLException e)
|
|
||||||
{
|
|
||||||
if(!resource.startsWith("ftp:") &&
|
|
||||||
!resource.startsWith("file:") &&
|
|
||||||
!resource.startsWith("jar:"))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// It's a file.
|
|
||||||
if (resource.startsWith("./"))
|
|
||||||
resource=resource.substring(2);
|
|
||||||
|
|
||||||
File file=new File(resource).getCanonicalFile();
|
|
||||||
url=file.toURI().toURL();
|
|
||||||
|
|
||||||
URLConnection connection=url.openConnection();
|
|
||||||
FileResource fileResource= new FileResource(url,connection,file);
|
|
||||||
return fileResource;
|
|
||||||
}
|
|
||||||
catch(Exception e2)
|
|
||||||
{
|
|
||||||
log.debug(LogSupport.EXCEPTION,e2);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.warn("Bad Resource: "+resource);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String nurl=url.toString();
|
|
||||||
if (nurl.length()>0 &&
|
|
||||||
nurl.charAt(nurl.length()-1)!=
|
|
||||||
resource.charAt(resource.length()-1))
|
|
||||||
{
|
|
||||||
if ((nurl.charAt(nurl.length()-1)!='/' ||
|
|
||||||
nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
|
|
||||||
&&
|
|
||||||
(resource.charAt(resource.length()-1)!='/' ||
|
|
||||||
resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
|
|
||||||
))
|
|
||||||
{
|
|
||||||
return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newResource(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Construct a system resource from a string.
|
|
||||||
* The resource is tried as classloader resource before being
|
|
||||||
* treated as a normal resource.
|
|
||||||
*/
|
|
||||||
public static Resource newSystemResource(String resource)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
URL url=null;
|
|
||||||
// Try to format as a URL?
|
|
||||||
ClassLoader
|
|
||||||
loader=Thread.currentThread().getContextClassLoader();
|
|
||||||
if (loader!=null)
|
|
||||||
{
|
|
||||||
url=loader.getResource(resource);
|
|
||||||
if (url==null && resource.startsWith("/"))
|
|
||||||
url=loader.getResource(resource.substring(1));
|
|
||||||
}
|
|
||||||
if (url==null)
|
|
||||||
{
|
|
||||||
loader=Resource.class.getClassLoader();
|
|
||||||
if (loader!=null)
|
|
||||||
{
|
|
||||||
url=loader.getResource(resource);
|
|
||||||
if (url==null && resource.startsWith("/"))
|
|
||||||
url=loader.getResource(resource.substring(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url==null)
|
|
||||||
{
|
|
||||||
url=ClassLoader.getSystemResource(resource);
|
|
||||||
if (url==null && resource.startsWith("/"))
|
|
||||||
url=loader.getResource(resource.substring(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url==null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return newResource(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
protected void finalize()
|
|
||||||
{
|
|
||||||
release();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Release any resources held by the resource.
|
|
||||||
*/
|
|
||||||
public abstract void release();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns true if the respresened resource exists.
|
|
||||||
*/
|
|
||||||
public abstract boolean exists();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns true if the respresenetd resource is a container/directory.
|
|
||||||
* If the resource is not a file, resources ending with "/" are
|
|
||||||
* considered directories.
|
|
||||||
*/
|
|
||||||
public abstract boolean isDirectory();
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns the last modified time
|
|
||||||
*/
|
|
||||||
public abstract long lastModified();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Return the length of the resource
|
|
||||||
*/
|
|
||||||
public abstract long length();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns an URL representing the given resource
|
|
||||||
*/
|
|
||||||
public abstract URL getURL();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns an File representing the given resource or NULL if this
|
|
||||||
* is not possible.
|
|
||||||
*/
|
|
||||||
public abstract File getFile()
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns the name of the resource
|
|
||||||
*/
|
|
||||||
public abstract String getName();
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns an input stream to the resource
|
|
||||||
*/
|
|
||||||
public abstract InputStream getInputStream()
|
|
||||||
throws java.io.IOException;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns an output stream to the resource
|
|
||||||
*/
|
|
||||||
public abstract OutputStream getOutputStream()
|
|
||||||
throws java.io.IOException, SecurityException;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Deletes the given resource
|
|
||||||
*/
|
|
||||||
public abstract boolean delete()
|
|
||||||
throws SecurityException;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Rename the given resource
|
|
||||||
*/
|
|
||||||
public abstract boolean renameTo( Resource dest)
|
|
||||||
throws SecurityException;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns a list of resource names contained in the given resource
|
|
||||||
* The resource names are not URL encoded.
|
|
||||||
*/
|
|
||||||
public abstract String[] list();
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* Returns the resource contained inside the current resource with the
|
|
||||||
* given name.
|
|
||||||
* @param path The path segment to add, which should be encoded by the
|
|
||||||
* encode method.
|
|
||||||
*/
|
|
||||||
public abstract Resource addPath(String path)
|
|
||||||
throws IOException,MalformedURLException;
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Encode according to this resource type.
|
|
||||||
* The default implementation calls URI.encodePath(uri)
|
|
||||||
* @param uri
|
|
||||||
* @return String encoded for this resource type.
|
|
||||||
*/
|
|
||||||
public String encode(String uri)
|
|
||||||
{
|
|
||||||
return URI.encodePath(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public Object getAssociate()
|
|
||||||
{
|
|
||||||
return _associate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public void setAssociate(Object o)
|
|
||||||
{
|
|
||||||
_associate=o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @return The canonical Alias of this resource or null if none.
|
|
||||||
*/
|
|
||||||
public URL getAlias()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
public CachedResource cache()
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
return new CachedResource(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/** Get the resource list as a HTML directory listing.
|
|
||||||
* @param base The base URL
|
|
||||||
* @param parent True if the parent directory should be included
|
|
||||||
* @return String of HTML
|
|
||||||
*/
|
|
||||||
public String getListHTML(String base,
|
|
||||||
boolean parent)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (!isDirectory())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
|
|
||||||
String[] ls = list();
|
|
||||||
if (ls==null)
|
|
||||||
return null;
|
|
||||||
Arrays.sort(ls);
|
|
||||||
|
|
||||||
String title = "Directory: "+URI.decodePath(base);
|
|
||||||
title=StringUtil.replace(StringUtil.replace(title,"<","<"),">",">");
|
|
||||||
StringBuffer buf=new StringBuffer(4096);
|
|
||||||
buf.append("<HTML><HEAD><TITLE>");
|
|
||||||
buf.append(title);
|
|
||||||
buf.append("</TITLE></HEAD><BODY>\n<H1>");
|
|
||||||
buf.append(title);
|
|
||||||
buf.append("</H1><TABLE BORDER=0>");
|
|
||||||
|
|
||||||
if (parent)
|
|
||||||
{
|
|
||||||
buf.append("<TR><TD><A HREF=");
|
|
||||||
buf.append(URI.encodePath(URI.addPaths(base,"../")));
|
|
||||||
buf.append(">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
|
|
||||||
DateFormat.MEDIUM);
|
|
||||||
for (int i=0 ; i< ls.length ; i++)
|
|
||||||
{
|
|
||||||
String encoded=URI.encodePath(ls[i]);
|
|
||||||
// bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times)
|
|
||||||
// http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs
|
|
||||||
// See resource.diff attachment
|
|
||||||
//Resource item = addPath(encoded);
|
|
||||||
Resource item = addPath(ls[i]);
|
|
||||||
|
|
||||||
buf.append("<TR><TD><A HREF=\"");
|
|
||||||
|
|
||||||
String path=URI.addPaths(base,encoded);
|
|
||||||
|
|
||||||
if (item.isDirectory() && !path.endsWith("/"))
|
|
||||||
path=URI.addPaths(path,"/");
|
|
||||||
buf.append(path);
|
|
||||||
buf.append("\">");
|
|
||||||
buf.append(StringUtil.replace(StringUtil.replace(ls[i],"<","<"),">",">"));
|
|
||||||
buf.append("</A> ");
|
|
||||||
buf.append("</TD><TD ALIGN=right>");
|
|
||||||
buf.append(item.length());
|
|
||||||
buf.append(" bytes </TD><TD>");
|
|
||||||
buf.append(dfmt.format(new Date(item.lastModified())));
|
|
||||||
buf.append("</TD></TR>\n");
|
|
||||||
}
|
|
||||||
buf.append("</TABLE>\n");
|
|
||||||
buf.append("</BODY></HTML>\n");
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
|
||||||
/**
|
|
||||||
* @param out
|
|
||||||
* @param start First byte to write
|
|
||||||
* @param count Bytes to write or -1 for all of them.
|
|
||||||
*/
|
|
||||||
public void writeTo(OutputStream out,long start,long count)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
InputStream in = getInputStream();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
in.skip(start);
|
|
||||||
if (count<0)
|
|
||||||
IO.copy(in,out);
|
|
||||||
else
|
|
||||||
IO.copy(in,out,(int)count);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,7 +21,11 @@
|
|||||||
<pathelement location="../../../core/java/build/obj" />
|
<pathelement location="../../../core/java/build/obj" />
|
||||||
<pathelement location="../../../router/java/build/obj" />
|
<pathelement location="../../../router/java/build/obj" />
|
||||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.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-threadpool.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<pathelement location="../../systray/java/build/obj" />
|
<pathelement location="../../systray/java/build/obj" />
|
||||||
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
||||||
<pathelement location="../../desktopgui/build" />
|
<pathelement location="../../desktopgui/build" />
|
||||||
@ -53,7 +57,11 @@
|
|||||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||||
<pathelement location="../../../router/java/build/router.jar" />
|
<pathelement location="../../../router/java/build/router.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.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-threadpool.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<pathelement location="../../systray/java/build/systray.jar" />
|
<pathelement location="../../systray/java/build/systray.jar" />
|
||||||
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
||||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||||
@ -233,6 +241,7 @@
|
|||||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.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/ant.jar" />
|
||||||
<pathelement location="../../systray/java/build/obj" />
|
<pathelement location="../../systray/java/build/obj" />
|
||||||
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
||||||
@ -266,6 +275,10 @@
|
|||||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.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-threadpool.jar" />
|
||||||
|
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||||
<pathelement location="../../systray/java/build/obj" />
|
<pathelement location="../../systray/java/build/obj" />
|
||||||
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
<pathelement location="../../systray/java/lib/systray4j.jar" />
|
||||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||||
|
@ -14,7 +14,7 @@ import net.i2p.router.client.ClientManagerFacadeImpl;
|
|||||||
import net.i2p.router.startup.ClientAppConfig;
|
import net.i2p.router.startup.ClientAppConfig;
|
||||||
import net.i2p.router.startup.LoadClientAppsJob;
|
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
|
* Saves changes to clients.config or webapps.config
|
||||||
@ -286,7 +286,7 @@ public class ConfigClientsHandler extends FormHandler {
|
|||||||
* requested and add the .war to that one
|
* requested and add the .war to that one
|
||||||
*/
|
*/
|
||||||
private void startWebApp(String app) {
|
private void startWebApp(String app) {
|
||||||
Server s = WebAppStarter.getConsoleServer();
|
ContextHandlerCollection s = WebAppStarter.getConsoleServer();
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
try {
|
try {
|
||||||
File path = new File(_context.getBaseDir(), "webapps");
|
File path = new File(_context.getBaseDir(), "webapps");
|
||||||
|
@ -4,11 +4,13 @@ import java.io.IOException;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
|
||||||
import org.mortbay.http.HttpRequest;
|
import org.mortbay.jetty.webapp.WebAppContext;
|
||||||
import org.mortbay.http.HttpResponse;
|
|
||||||
import org.mortbay.jetty.servlet.WebApplicationHandler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert foo.jsp to foo_xx.jsp for language xx.
|
* Convert foo.jsp to foo_xx.jsp for language xx.
|
||||||
@ -19,12 +21,12 @@ import org.mortbay.jetty.servlet.WebApplicationHandler;
|
|||||||
*
|
*
|
||||||
* @author zzz
|
* @author zzz
|
||||||
*/
|
*/
|
||||||
public class LocaleWebAppHandler extends WebApplicationHandler
|
public class LocaleWebAppHandler extends WebAppContext
|
||||||
{
|
{
|
||||||
private final I2PAppContext _context;
|
private final I2PAppContext _context;
|
||||||
|
|
||||||
public LocaleWebAppHandler(I2PAppContext ctx) {
|
public LocaleWebAppHandler(I2PAppContext ctx, String path, String warPath) {
|
||||||
super();
|
super(warPath, path);
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,13 +38,13 @@ public class LocaleWebAppHandler extends WebApplicationHandler
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void handle(String pathInContext,
|
public void handle(String pathInContext,
|
||||||
String pathParams,
|
HttpServletRequest httpRequest,
|
||||||
HttpRequest httpRequest,
|
HttpServletResponse httpResponse,
|
||||||
HttpResponse httpResponse)
|
int dispatch)
|
||||||
throws IOException
|
throws IOException, ServletException
|
||||||
{
|
{
|
||||||
// Handle OPTIONS (nothing to override)
|
// Handle OPTIONS (nothing to override)
|
||||||
if (HttpRequest.__OPTIONS.equals(httpRequest.getMethod()))
|
if ("OPTIONS".equals(httpRequest.getMethod()))
|
||||||
{
|
{
|
||||||
handleOptions(httpRequest, httpResponse);
|
handleOptions(httpRequest, httpResponse);
|
||||||
return;
|
return;
|
||||||
@ -74,7 +76,9 @@ public class LocaleWebAppHandler extends WebApplicationHandler
|
|||||||
if (lang != null && lang.length() > 0 && !lang.equals("en")) {
|
if (lang != null && lang.length() > 0 && !lang.equals("en")) {
|
||||||
String testPath = pathInContext.substring(0, len - 4) + '_' + lang + ".jsp";
|
String testPath = pathInContext.substring(0, len - 4) + '_' + lang + ".jsp";
|
||||||
// Do we have a servlet for the new path that isn't the catchall *.jsp?
|
// Do we have a servlet for the new path that isn't the catchall *.jsp?
|
||||||
Map.Entry servlet = getHolderEntry(testPath);
|
//Map.Entry servlet = getHolderEntry(testPath);
|
||||||
|
///////////////////////////////
|
||||||
|
Map.Entry servlet = null;
|
||||||
if (servlet != null) {
|
if (servlet != null) {
|
||||||
String servletPath = (String) servlet.getKey();
|
String servletPath = (String) servlet.getKey();
|
||||||
if (servletPath != null && !servletPath.startsWith("*")) {
|
if (servletPath != null && !servletPath.startsWith("*")) {
|
||||||
@ -87,7 +91,7 @@ public class LocaleWebAppHandler extends WebApplicationHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//System.err.println("New path: " + newPath);
|
//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());
|
//System.err.println("Was handled? " + httpRequest.isHandled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,22 +99,24 @@ public class LocaleWebAppHandler extends WebApplicationHandler
|
|||||||
* Overrides method in ServletHandler
|
* Overrides method in ServletHandler
|
||||||
* @since 0.8
|
* @since 0.8
|
||||||
*/
|
*/
|
||||||
|
/**** not in Jetty 6
|
||||||
@Override
|
@Override
|
||||||
public void handleTrace(HttpRequest request,
|
public void handleTrace(HttpServletRequest request,
|
||||||
HttpResponse response)
|
HttpServletResponse response)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed);
|
response.sendError(405);
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not an override
|
* Not an override
|
||||||
* @since 0.8
|
* @since 0.8
|
||||||
*/
|
*/
|
||||||
public void handleOptions(HttpRequest request,
|
public void handleOptions(HttpServletRequest request,
|
||||||
HttpResponse response)
|
HttpServletResponse response)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
response.sendError(HttpResponse.__405_Method_Not_Allowed);
|
response.sendError(405);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@ import java.util.List;
|
|||||||
|
|
||||||
import net.i2p.util.FileUtil;
|
import net.i2p.util.FileUtil;
|
||||||
|
|
||||||
import org.mortbay.http.Version;
|
import org.mortbay.jetty.Server;
|
||||||
|
|
||||||
public class LogsHelper extends HelperBase {
|
public class LogsHelper extends HelperBase {
|
||||||
public LogsHelper() {}
|
public LogsHelper() {}
|
||||||
|
|
||||||
/** @since 0.8.11 */
|
/** @since 0.8.11 */
|
||||||
public String getJettyVersion() {
|
public String getJettyVersion() {
|
||||||
return Version.getImplVersion();
|
return Server.getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLogs() {
|
public String getLogs() {
|
||||||
|
@ -28,7 +28,7 @@ import net.i2p.util.FileUtil;
|
|||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
|
|
||||||
import org.mortbay.jetty.Server;
|
import org.mortbay.jetty.handler.ContextHandlerCollection;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,7 +120,7 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start console webapps in console/webapps
|
// start console webapps in console/webapps
|
||||||
Server server = WebAppStarter.getConsoleServer();
|
ContextHandlerCollection server = WebAppStarter.getConsoleServer();
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
File consoleDir = new File(pluginDir, "console");
|
File consoleDir = new File(pluginDir, "console");
|
||||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||||
@ -221,8 +221,8 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stop console webapps in console/webapps
|
// stop console webapps in console/webapps
|
||||||
Server server = WebAppStarter.getConsoleServer();
|
//ContextHandlerCollection server = WebAppStarter.getConsoleServer();
|
||||||
if (server != null) {
|
//if (server != null) {
|
||||||
/*
|
/*
|
||||||
File consoleDir = new File(pluginDir, "console");
|
File consoleDir = new File(pluginDir, "console");
|
||||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||||
@ -242,11 +242,11 @@ public class PluginStarter implements Runnable {
|
|||||||
Iterator <String> wars = pluginWars.get(appName).iterator();
|
Iterator <String> wars = pluginWars.get(appName).iterator();
|
||||||
while (wars.hasNext()) {
|
while (wars.hasNext()) {
|
||||||
String warName = wars.next();
|
String warName = wars.next();
|
||||||
WebAppStarter.stopWebApp(server, warName);
|
WebAppStarter.stopWebApp(warName);
|
||||||
}
|
}
|
||||||
pluginWars.get(appName).clear();
|
pluginWars.get(appName).clear();
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
|
|
||||||
// remove summary bar link
|
// remove summary bar link
|
||||||
Properties props = pluginProperties(ctx, appName);
|
Properties props = pluginProperties(ctx, appName);
|
||||||
|
@ -9,6 +9,7 @@ import java.security.KeyStore;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.apps.systray.SysTray;
|
import net.i2p.apps.systray.SysTray;
|
||||||
@ -24,25 +25,39 @@ import net.i2p.util.SecureFileOutputStream;
|
|||||||
import net.i2p.util.ShellCommand;
|
import net.i2p.util.ShellCommand;
|
||||||
import net.i2p.util.VersionComparator;
|
import net.i2p.util.VersionComparator;
|
||||||
|
|
||||||
import org.mortbay.http.DigestAuthenticator;
|
import org.mortbay.jetty.AbstractConnector;
|
||||||
import org.mortbay.http.HashUserRealm;
|
import org.mortbay.jetty.Connector;
|
||||||
import org.mortbay.http.NCSARequestLog;
|
import org.mortbay.jetty.Handler;
|
||||||
import org.mortbay.http.SecurityConstraint;
|
import org.mortbay.jetty.NCSARequestLog;
|
||||||
import org.mortbay.http.SocketListener;
|
|
||||||
import org.mortbay.http.SslListener;
|
|
||||||
import org.mortbay.http.handler.SecurityHandler;
|
|
||||||
import org.mortbay.jetty.Server;
|
import org.mortbay.jetty.Server;
|
||||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
import org.mortbay.jetty.handler.ContextHandlerCollection;
|
||||||
import org.mortbay.jetty.servlet.WebApplicationHandler;
|
import org.mortbay.jetty.handler.DefaultHandler;
|
||||||
import org.mortbay.util.InetAddrPort;
|
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.SessionHandler;
|
||||||
|
import org.mortbay.jetty.webapp.WebAppContext;
|
||||||
|
import org.mortbay.thread.QueuedThreadPool;
|
||||||
|
import org.mortbay.thread.concurrent.ThreadPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the router console.
|
||||||
|
*/
|
||||||
public class RouterConsoleRunner {
|
public class RouterConsoleRunner {
|
||||||
private Server _server;
|
private static Server _server;
|
||||||
private String _listenPort;
|
private String _listenPort;
|
||||||
private String _listenHost;
|
private String _listenHost;
|
||||||
private String _sslListenPort;
|
private String _sslListenPort;
|
||||||
private String _sslListenHost;
|
private String _sslListenHost;
|
||||||
private String _webAppsDir;
|
private String _webAppsDir;
|
||||||
|
|
||||||
private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile";
|
private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile";
|
||||||
private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
|
private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
|
||||||
private static final DigestAuthenticator authenticator = new DigestAuthenticator();
|
private static final DigestAuthenticator authenticator = new DigestAuthenticator();
|
||||||
@ -57,6 +72,10 @@ public class RouterConsoleRunner {
|
|||||||
private static final String DEFAULT_WEBAPPS_DIR = "./webapps/";
|
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! " +
|
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]]";
|
"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;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.setProperty("org.mortbay.http.Version.paranoid", "true");
|
System.setProperty("org.mortbay.http.Version.paranoid", "true");
|
||||||
@ -135,6 +154,15 @@ public class RouterConsoleRunner {
|
|||||||
runner.startConsole();
|
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() {
|
private static void startTrayApp() {
|
||||||
try {
|
try {
|
||||||
//TODO: move away from routerconsole into a separate application.
|
//TODO: move away from routerconsole into a separate application.
|
||||||
@ -158,6 +186,23 @@ public class RouterConsoleRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://irc.codehaus.org/display/JETTY/Porting+to+jetty6
|
||||||
|
*
|
||||||
|
*<pre>
|
||||||
|
* Server
|
||||||
|
* HandlerCollection
|
||||||
|
* ContextHandlerCollection
|
||||||
|
* WebAppContext (i.e. ContextHandler)
|
||||||
|
* SessionHandler
|
||||||
|
* SecurityHandler
|
||||||
|
* ServletHandler
|
||||||
|
* WebAppContext
|
||||||
|
* ...
|
||||||
|
* DefaultHandler
|
||||||
|
* RequestLogHandler (opt)
|
||||||
|
*</pre>
|
||||||
|
*/
|
||||||
public void startConsole() {
|
public void startConsole() {
|
||||||
File workDir = new SecureDirectory(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
|
File workDir = new SecureDirectory(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
|
||||||
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
|
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
|
||||||
@ -171,14 +216,34 @@ public class RouterConsoleRunner {
|
|||||||
System.setProperty("jetty.class.path", I2PAppContext.getGlobalContext().getBaseDir() + "/lib/routerconsole.jar");
|
System.setProperty("jetty.class.path", I2PAppContext.getGlobalContext().getBaseDir() + "/lib/routerconsole.jar");
|
||||||
_server = new Server();
|
_server = new Server();
|
||||||
|
|
||||||
|
/**** this doesn't work with NIO maybe?
|
||||||
|
try {
|
||||||
|
_server.setThreadPool(new ThreadPool(MIN_THREADS, MAX_THREADS, MAX_IDLE_TIME, TimeUnit.MILLISECONDS));
|
||||||
|
} 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");
|
String log = I2PAppContext.getGlobalContext().getProperty("routerconsole.log");
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
File logFile = new File(log);
|
File logFile = new File(log);
|
||||||
if (!logFile.isAbsolute())
|
if (!logFile.isAbsolute())
|
||||||
logFile = new File(I2PAppContext.getGlobalContext().getLogDir(), "logs/" + log);
|
logFile = new File(I2PAppContext.getGlobalContext().getLogDir(), "logs/" + log);
|
||||||
try {
|
try {
|
||||||
_server.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
|
RequestLogHandler rhl = new RequestLogHandler();
|
||||||
} catch (IOException ioe) {
|
rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
|
||||||
|
hColl.addHandler(rhl);
|
||||||
|
} catch (Exception ioe) {
|
||||||
System.err.println("ERROR: Unable to create Jetty log: " + ioe);
|
System.err.println("ERROR: Unable to create Jetty log: " + ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +267,7 @@ public class RouterConsoleRunner {
|
|||||||
_webAppsDir += '/';
|
_webAppsDir += '/';
|
||||||
|
|
||||||
List<String> notStarted = new ArrayList();
|
List<String> notStarted = new ArrayList();
|
||||||
WebApplicationHandler baseHandler = null;
|
WebAppContext baseHandler = null;
|
||||||
try {
|
try {
|
||||||
int boundAddresses = 0;
|
int boundAddresses = 0;
|
||||||
|
|
||||||
@ -217,17 +282,17 @@ public class RouterConsoleRunner {
|
|||||||
// _server.addListener('[' + host + "]:" + _listenPort);
|
// _server.addListener('[' + host + "]:" + _listenPort);
|
||||||
//else
|
//else
|
||||||
// _server.addListener(host + ':' + _listenPort);
|
// _server.addListener(host + ':' + _listenPort);
|
||||||
InetAddrPort iap = new InetAddrPort(host, lport);
|
// Use AbstractConnector instead of Connector so we can do setName()
|
||||||
SocketListener lsnr = new SocketListener(iap);
|
AbstractConnector lsnr = new SelectChannelConnector();
|
||||||
lsnr.setMinThreads(1); // default 2
|
lsnr.setHost(host);
|
||||||
lsnr.setMaxThreads(24); // default 256
|
lsnr.setPort(lport);
|
||||||
lsnr.setMaxIdleTimeMs(90*1000); // default 10 sec
|
lsnr.setMaxIdleTime(90*1000); // default 10 sec
|
||||||
lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
||||||
_server.addListener(lsnr);
|
_server.addConnector(lsnr);
|
||||||
boundAddresses++;
|
boundAddresses++;
|
||||||
} catch (NumberFormatException nfe) {
|
} catch (NumberFormatException nfe) {
|
||||||
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + 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);
|
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,19 +317,20 @@ public class RouterConsoleRunner {
|
|||||||
while (tok.hasMoreTokens()) {
|
while (tok.hasMoreTokens()) {
|
||||||
String host = tok.nextToken().trim();
|
String host = tok.nextToken().trim();
|
||||||
// doing it this way means we don't have to escape an IPv6 host with []
|
// doing it this way means we don't have to escape an IPv6 host with []
|
||||||
InetAddrPort iap = new InetAddrPort(host, sslPort);
|
|
||||||
try {
|
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
|
// the keystore path and password
|
||||||
ssll.setKeystore(keyStore.getAbsolutePath());
|
ssll.setKeystore(keyStore.getAbsolutePath());
|
||||||
ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||||
// the X.509 cert password (if not present, verifyKeyStore() returned false)
|
// the X.509 cert password (if not present, verifyKeyStore() returned false)
|
||||||
ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||||
ssll.setMinThreads(1); // default 2
|
ssll.setMaxIdleTime(90*1000); // default 10 sec
|
||||||
ssll.setMaxThreads(24); // default 256
|
|
||||||
ssll.setMaxIdleTimeMs(90*1000); // default 10 sec
|
|
||||||
ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool
|
||||||
_server.addListener(ssll);
|
_server.addConnector(ssll);
|
||||||
boundAddresses++;
|
boundAddresses++;
|
||||||
} catch (Exception e) { // probably no exceptions at this point
|
} catch (Exception e) { // probably no exceptions at this point
|
||||||
System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
|
System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
|
||||||
@ -280,15 +346,18 @@ public class RouterConsoleRunner {
|
|||||||
System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
|
System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_server.setRootWebApp(ROUTERCONSOLE);
|
|
||||||
WebApplicationContext wac = _server.addWebApplication("/", _webAppsDir + ROUTERCONSOLE + ".war");
|
baseHandler = new LocaleWebAppHandler(I2PAppContext.getGlobalContext(),
|
||||||
|
"/", _webAppsDir + ROUTERCONSOLE + ".war");
|
||||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
||||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||||
tmpdir.mkdir();
|
tmpdir.mkdir();
|
||||||
wac.setTempDirectory(tmpdir);
|
baseHandler.setTempDirectory(tmpdir);
|
||||||
baseHandler = new LocaleWebAppHandler(I2PAppContext.getGlobalContext());
|
baseHandler.setSessionHandler(new SessionHandler());
|
||||||
wac.addHandler(0, baseHandler);
|
baseHandler.setServletHandler(new ServletHandler());
|
||||||
initialize(wac);
|
initialize(baseHandler);
|
||||||
|
chColl.addHandler(baseHandler);
|
||||||
|
|
||||||
File dir = new File(_webAppsDir);
|
File dir = new File(_webAppsDir);
|
||||||
String fileNames[] = dir.list(WarFilenameFilter.instance());
|
String fileNames[] = dir.list(WarFilenameFilter.instance());
|
||||||
if (fileNames != null) {
|
if (fileNames != null) {
|
||||||
@ -300,7 +369,7 @@ public class RouterConsoleRunner {
|
|||||||
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
||||||
tmpdir = new SecureDirectory(workDir, appName + "-" +
|
tmpdir = new SecureDirectory(workDir, appName + "-" +
|
||||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||||
WebAppStarter.addWebApp(I2PAppContext.getGlobalContext(), _server, appName, path, tmpdir);
|
WebAppStarter.addWebApp(I2PAppContext.getGlobalContext(), chColl, appName, path, tmpdir);
|
||||||
|
|
||||||
if (enabled == null) {
|
if (enabled == null) {
|
||||||
// do this so configclients.jsp knows about all apps from reading the config
|
// do this so configclients.jsp knows about all apps from reading the config
|
||||||
@ -315,12 +384,14 @@ public class RouterConsoleRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (Exception ioe) {
|
||||||
ioe.printStackTrace();
|
ioe.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rewrite)
|
if (rewrite)
|
||||||
storeWebAppProperties(props);
|
storeWebAppProperties(props);
|
||||||
try {
|
try {
|
||||||
|
// start does a mapContexts()
|
||||||
_server.start();
|
_server.start();
|
||||||
} catch (Throwable me) {
|
} catch (Throwable me) {
|
||||||
// NoClassFoundDefError from a webapp is a throwable, not an exception
|
// NoClassFoundDefError from a webapp is a throwable, not an exception
|
||||||
@ -337,8 +408,9 @@ public class RouterConsoleRunner {
|
|||||||
// map each not-started webapp to the error page
|
// map each not-started webapp to the error page
|
||||||
for (int i = 0; i < notStarted.size(); i++) {
|
for (int i = 0; i < notStarted.size(); i++) {
|
||||||
try {
|
try {
|
||||||
baseHandler.mapPathToServlet('/' + notStarted.get(i) + "/*",
|
/////////////////////////////////////////////////
|
||||||
"net.i2p.router.web.jsp.nowebapp_jsp");
|
//baseHandler.mapPathToServlet('/' + notStarted.get(i) + "/*",
|
||||||
|
// "net.i2p.router.web.jsp.nowebapp_jsp");
|
||||||
} catch (Throwable me) {
|
} catch (Throwable me) {
|
||||||
System.err.println(me);
|
System.err.println(me);
|
||||||
}
|
}
|
||||||
@ -454,18 +526,22 @@ public class RouterConsoleRunner {
|
|||||||
return success;
|
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();
|
String password = getPassword();
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
HashUserRealm realm = new HashUserRealm("i2prouter");
|
HashUserRealm realm = new HashUserRealm("i2prouter");
|
||||||
realm.put("admin", password);
|
realm.put("admin", password);
|
||||||
realm.addUserToRole("admin", "routerAdmin");
|
realm.addUserToRole("admin", "routerAdmin");
|
||||||
context.setRealm(realm);
|
sec.setUserRealm(realm);
|
||||||
context.setAuthenticator(authenticator);
|
sec.setAuthenticator(authenticator);
|
||||||
context.addHandler(0, new SecurityHandler());
|
Constraint constraint = new Constraint("admin", "routerAdmin");
|
||||||
SecurityConstraint constraint = new SecurityConstraint("admin", "routerAdmin");
|
|
||||||
constraint.setAuthenticate(true);
|
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
|
// This forces a '403 Forbidden' response for TRACE and OPTIONS unless the
|
||||||
@ -477,12 +553,27 @@ public class RouterConsoleRunner {
|
|||||||
// The other strange methods - PUT, DELETE, MOVE - are disabled by default
|
// The other strange methods - PUT, DELETE, MOVE - are disabled by default
|
||||||
// See also:
|
// See also:
|
||||||
// http://old.nabble.com/Disable-HTTP-TRACE-in-Jetty-5.x-td12412607.html
|
// http://old.nabble.com/Disable-HTTP-TRACE-in-Jetty-5.x-td12412607.html
|
||||||
SecurityConstraint sc = new SecurityConstraint();
|
|
||||||
sc.setName("No trace or options");
|
Constraint sc = new Constraint();
|
||||||
sc.addMethod("TRACE");
|
sc.setName("No trace");
|
||||||
sc.addMethod("OPTIONS");
|
ConstraintMapping cm = new ConstraintMapping();
|
||||||
sc.setAuthenticate(true);
|
cm.setMethod("TRACE");
|
||||||
context.addSecurityConstraint("/*", sc) ;
|
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() {
|
static String getPassword() {
|
||||||
@ -507,11 +598,11 @@ public class RouterConsoleRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.8.8 */
|
/** @since 0.8.8 */
|
||||||
private class ServerShutdown implements Runnable {
|
private static class ServerShutdown implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
_server.stop();
|
_server.stop();
|
||||||
} catch (InterruptedException ie) {}
|
} catch (Exception ie) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ import java.util.StringTokenizer;
|
|||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
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
|
* @since 0.7.12
|
||||||
* @author zzz
|
* @author zzz
|
||||||
*/
|
*/
|
||||||
public class WebAppConfiguration implements WebApplicationContext.Configuration {
|
public class WebAppConfiguration implements Configuration {
|
||||||
private WebApplicationContext _wac;
|
private WebAppContext _wac;
|
||||||
|
|
||||||
private static final String CLASSPATH = ".classpath";
|
private static final String CLASSPATH = ".classpath";
|
||||||
|
|
||||||
public void setWebApplicationContext(WebApplicationContext context) {
|
public void setWebAppContext(WebAppContext context) {
|
||||||
_wac = context;
|
_wac = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebApplicationContext getWebApplicationContext() {
|
public WebAppContext getWebAppContext() {
|
||||||
return _wac;
|
return _wac;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,10 +88,16 @@ public class WebAppConfiguration implements WebApplicationContext.Configuration
|
|||||||
else
|
else
|
||||||
path = dir.getAbsolutePath() + '/' + elem;
|
path = dir.getAbsolutePath() + '/' + elem;
|
||||||
System.err.println("Adding " + path + " to classpath for " + appName);
|
System.err.println("Adding " + path + " to classpath for " + appName);
|
||||||
_wac.addClassPath(path);
|
_wac.setExtraClasspath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configureDefaults() {}
|
public void configureDefaults() {}
|
||||||
public void configureWebApp() {}
|
public void configureWebApp() {}
|
||||||
|
|
||||||
|
/** @since Jetty 6 */
|
||||||
|
public void deconfigureWebApp() {}
|
||||||
|
|
||||||
|
/** @since Jetty 6 */
|
||||||
|
public void configureClassLoader() {}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,12 @@ import net.i2p.util.Log;
|
|||||||
import net.i2p.util.SecureDirectory;
|
import net.i2p.util.SecureDirectory;
|
||||||
import net.i2p.util.PortMapper;
|
import net.i2p.util.PortMapper;
|
||||||
|
|
||||||
import org.mortbay.http.HttpContext;
|
import org.mortbay.jetty.Connector;
|
||||||
import org.mortbay.http.HttpListener;
|
import org.mortbay.jetty.Handler;
|
||||||
import org.mortbay.jetty.Server;
|
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
|
* adds and starts
|
||||||
* @throws just about anything, caller would be wise to catch Throwable
|
* @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());
|
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);
|
_log.debug("Loading war from: " + warPath);
|
||||||
wac.start();
|
wac.start();
|
||||||
}
|
}
|
||||||
@ -61,12 +64,13 @@ public class WebAppStarter {
|
|||||||
* This is used only by RouterConsoleRunner, which adds all the webapps first
|
* This is used only by RouterConsoleRunner, which adds all the webapps first
|
||||||
* and then starts all at once.
|
* 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
|
// Jetty will happily load one context on top of another without stopping
|
||||||
// the first one, so we remove any previous one here
|
// the first one, so we remove any previous one here
|
||||||
try {
|
try {
|
||||||
stopWebApp(server, appName);
|
stopWebApp(appName);
|
||||||
} catch (Throwable t) {}
|
} catch (Throwable t) {}
|
||||||
|
|
||||||
// To avoid ZipErrors from JarURLConnetion caching,
|
// To avoid ZipErrors from JarURLConnetion caching,
|
||||||
@ -91,7 +95,7 @@ public class WebAppStarter {
|
|||||||
warPath = tmpPath;
|
warPath = tmpPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebApplicationContext wac = server.addWebApplication("/"+ appName, warPath);
|
WebAppContext wac = new WebAppContext(warPath, "/"+ appName);
|
||||||
tmpdir.mkdir();
|
tmpdir.mkdir();
|
||||||
wac.setTempDirectory(tmpdir);
|
wac.setTempDirectory(tmpdir);
|
||||||
|
|
||||||
@ -101,12 +105,14 @@ public class WebAppStarter {
|
|||||||
|
|
||||||
|
|
||||||
// see WebAppConfiguration for info
|
// see WebAppConfiguration for info
|
||||||
String[] classNames = server.getWebApplicationConfigurationClassNames();
|
String[] classNames = wac.getConfigurationClasses();
|
||||||
String[] newClassNames = new String[classNames.length + 1];
|
String[] newClassNames = new String[classNames.length + 1];
|
||||||
for (int j = 0; j < classNames.length; j++)
|
for (int j = 0; j < classNames.length; j++)
|
||||||
newClassNames[j] = classNames[j];
|
newClassNames[j] = classNames[j];
|
||||||
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
newClassNames[classNames.length] = WebAppConfiguration.class.getName();
|
||||||
wac.setConfigurationClassNames(newClassNames);
|
wac.setConfigurationClasses(newClassNames);
|
||||||
|
server.addHandler(wac);
|
||||||
|
server.mapContexts();
|
||||||
return wac;
|
return wac;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,38 +120,55 @@ public class WebAppStarter {
|
|||||||
* stop it and remove the context
|
* stop it and remove the context
|
||||||
* @throws just about anything, caller would be wise to catch Throwable
|
* @throws just about anything, caller would be wise to catch Throwable
|
||||||
*/
|
*/
|
||||||
static void stopWebApp(Server server, String appName) {
|
static void stopWebApp(String appName) {
|
||||||
// this will return a new context if one does not exist
|
ContextHandler wac = getWebApp(appName);
|
||||||
HttpContext wac = server.getContext('/' + appName);
|
if (wac == null)
|
||||||
|
return;
|
||||||
try {
|
try {
|
||||||
// false -> not graceful
|
// not graceful is default in Jetty 6?
|
||||||
wac.stop(false);
|
wac.stop();
|
||||||
} catch (InterruptedException ie) {}
|
} catch (Exception ie) {}
|
||||||
|
ContextHandlerCollection server = getConsoleServer();
|
||||||
|
if (server == null)
|
||||||
|
return;
|
||||||
try {
|
try {
|
||||||
server.removeContext(wac);
|
server.removeHandler(wac);
|
||||||
|
server.mapContexts();
|
||||||
} catch (IllegalStateException ise) {}
|
} catch (IllegalStateException ise) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isWebAppRunning(String appName) {
|
static boolean isWebAppRunning(String appName) {
|
||||||
Server server = WebAppStarter.getConsoleServer();
|
ContextHandler wac = getWebApp(appName);
|
||||||
if (server == null)
|
if (wac == null)
|
||||||
return false;
|
return false;
|
||||||
// this will return a new context if one does not exist
|
|
||||||
HttpContext wac = server.getContext('/' + appName);
|
|
||||||
return wac.isStarted();
|
return wac.isStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** see comments in ConfigClientsHandler */
|
/** @since Jetty 6 */
|
||||||
static Server getConsoleServer() {
|
static ContextHandler getWebApp(String appName) {
|
||||||
Collection c = Server.getHttpServers();
|
ContextHandlerCollection server = getConsoleServer();
|
||||||
for (int i = 0; i < c.size(); i++) {
|
if (server == null)
|
||||||
Server s = (Server) c.toArray()[i];
|
return null;
|
||||||
HttpListener[] hl = s.getListeners();
|
Handler handlers[] = server.getHandlers();
|
||||||
for (int j = 0; j < hl.length; j++) {
|
if (handlers == null)
|
||||||
if (hl[j].getPort() == I2PAppContext.getGlobalContext().portMapper().getPort(PortMapper.SVC_CONSOLE))
|
return null;
|
||||||
return s;
|
String path = '/'+ appName;
|
||||||
}
|
for (int i = 0; i < handlers.length; i++) {
|
||||||
|
ContextHandler ch = (ContextHandler) handlers[i];
|
||||||
|
if (appName.equals(ch.getContextPath()))
|
||||||
|
return ch;
|
||||||
}
|
}
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
<pathelement location="${lib}/jasper-compiler.jar" />
|
<pathelement location="${lib}/jasper-compiler.jar" />
|
||||||
<pathelement location="${lib}/jasper-runtime.jar" />
|
<pathelement location="${lib}/jasper-runtime.jar" />
|
||||||
<pathelement location="${lib}/javax.servlet.jar" />
|
<pathelement location="${lib}/javax.servlet.jar" />
|
||||||
|
<pathelement location="${lib}/jsp-api.jar" />
|
||||||
<pathelement location="${lib}/commons-logging.jar" />
|
<pathelement location="${lib}/commons-logging.jar" />
|
||||||
<pathelement location="${lib}/commons-el.jar" />
|
<pathelement location="${lib}/commons-el.jar" />
|
||||||
<pathelement location="${lib}/ant.jar" />
|
<pathelement location="${lib}/ant.jar" />
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
|
||||||
<pathelement location="../jetty/jettylib/org.mortbay.jetty.jar" />
|
<pathelement location="../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||||
|
<pathelement location="../jetty/jettylib/jetty-util.jar" />
|
||||||
<pathelement location="../../core/java/build/i2p.jar" />
|
<pathelement location="../../core/java/build/i2p.jar" />
|
||||||
</classpath>
|
</classpath>
|
||||||
</javac>
|
</javac>
|
||||||
|
@ -15,4 +15,26 @@
|
|||||||
<session-config>
|
<session-config>
|
||||||
<session-timeout>15</session-timeout>
|
<session-timeout>15</session-timeout>
|
||||||
</session-config>
|
</session-config>
|
||||||
</web-app>
|
|
||||||
|
<!--
|
||||||
|
Jetty 6 mulipart form handling
|
||||||
|
See http://docs.codehaus.org/display/JETTY/File+Upload+in+jetty6
|
||||||
|
and RequestWrapper.java.
|
||||||
|
Unused because it doesn't support content-type until Jetty 8.
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<filter-name>fileuploadfilter</filter-name>
|
||||||
|
<filter-class>org.mortbay.servlet.MultiPartFilter</filter-class>
|
||||||
|
<init-param>
|
||||||
|
<param-name>deleteFiles</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>fileuploadfilter</filter-name>
|
||||||
|
<url-pattern>/susimail</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
-->
|
||||||
|
|
||||||
|
-</web-app>
|
||||||
|
@ -35,6 +35,19 @@ import javax.servlet.http.HttpSession;
|
|||||||
import org.mortbay.servlet.MultiPartRequest;
|
import org.mortbay.servlet.MultiPartRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Required major changes for Jetty 6
|
||||||
|
* to support change from MultiPartRequest to MultiPartFilter.
|
||||||
|
* See http://docs.codehaus.org/display/JETTY/File+Upload+in+jetty6
|
||||||
|
* Unfortunately, Content-type not available until Jetty 8
|
||||||
|
* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=349110
|
||||||
|
*
|
||||||
|
* So we could either extend and fix MultiPartFilter, and rewrite everything here,
|
||||||
|
* or copy MultiParRequest into our war and fix it so it compiles with Jetty 6.
|
||||||
|
* We do the latter.
|
||||||
|
*
|
||||||
|
* The filter would have been added in web.xml,
|
||||||
|
* see that file, where it's commented out.
|
||||||
|
*
|
||||||
* @author user
|
* @author user
|
||||||
*/
|
*/
|
||||||
public class RequestWrapper {
|
public class RequestWrapper {
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
# Javadocs
|
# Javadocs
|
||||||
# Note: Include the trailing slash! Don't surround the URL in quotes!
|
# Note: Include the trailing slash! Don't surround the URL in quotes!
|
||||||
javasedocs.url=http://docs.oracle.com/javase/6/docs/api/
|
javasedocs.url=http://docs.oracle.com/javase/6/docs/api/
|
||||||
jettydocs.url=http://docs.i2p2.de/jetty/javadoc/
|
jettydocs.url=http://jetty.codehaus.org/jetty/jetty-6/apidocs/
|
||||||
jrobindocs.url=http://docs.i2p-projekt.de/jrobin/javadoc/
|
jrobindocs.url=http://docs.i2p-projekt.de/jrobin/javadoc/
|
||||||
wrapperdocs.url=http://wrapper.tanukisoftware.com/jdoc/
|
wrapperdocs.url=http://wrapper.tanukisoftware.com/jdoc/
|
||||||
|
55
build.xml
@ -194,12 +194,9 @@
|
|||||||
<target name="buildWEB" depends="buildRouterConsole" >
|
<target name="buildWEB" depends="buildRouterConsole" >
|
||||||
<copy file="apps/routerconsole/java/build/routerconsole.jar" todir="build/" />
|
<copy file="apps/routerconsole/java/build/routerconsole.jar" todir="build/" />
|
||||||
<copy file="apps/routerconsole/java/build/routerconsole.war" todir="build/" />
|
<copy file="apps/routerconsole/java/build/routerconsole.war" todir="build/" />
|
||||||
<copy file="apps/jetty/jettylib/org.mortbay.jetty.jar" todir="build/" />
|
<copy todir="build/" >
|
||||||
<copy file="apps/jetty/jettylib/jasper-compiler.jar" todir="build/" />
|
<fileset dir="apps/jetty/jettylib" excludes="ant.jar" />
|
||||||
<copy file="apps/jetty/jettylib/jasper-runtime.jar" todir="build/" />
|
</copy>
|
||||||
<copy file="apps/jetty/jettylib/commons-logging.jar" todir="build/" />
|
|
||||||
<copy file="apps/jetty/jettylib/commons-el.jar" todir="build/" />
|
|
||||||
<copy file="apps/jetty/jettylib/javax.servlet.jar" todir="build/" />
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="buildexe">
|
<target name="buildexe">
|
||||||
@ -391,9 +388,10 @@
|
|||||||
<group title="Desktopgui Application" packages="net.i2p.desktopgui.*" />
|
<group title="Desktopgui Application" packages="net.i2p.desktopgui.*" />
|
||||||
<group title="I2PSnark Application" packages="org.klomp.snark:org.klomp.snark.*" />
|
<group title="I2PSnark Application" packages="org.klomp.snark:org.klomp.snark.*" />
|
||||||
<group title="I2PTunnel Application" packages="net.i2p.i2ptunnel:net.i2p.i2ptunnel.*" />
|
<group title="I2PTunnel Application" packages="net.i2p.i2ptunnel:net.i2p.i2ptunnel.*" />
|
||||||
|
<group title="Jetty Logging" packages="org.mortbay.http" />
|
||||||
<group title="SAM Bridge" packages="net.i2p.sam:net.i2p.sam.client" />
|
<group title="SAM Bridge" packages="net.i2p.sam:net.i2p.sam.client" />
|
||||||
<group title="SusiDNS Application" packages="i2p.susi.dns" />
|
<group title="SusiDNS Application" packages="i2p.susi.dns" />
|
||||||
<group title="SusiMail Application" packages="i2p.susi.webmail:i2p.susi.webmail.*:i2p.susi.debug:i2p.susi.util" />
|
<group title="SusiMail Application" packages="i2p.susi.webmail:i2p.susi.webmail.*:i2p.susi.debug:i2p.susi.util:org.mortbay.servlet:org.mortbay.util" />
|
||||||
<group title="Systray Application" packages="net.i2p.apps.systray" />
|
<group title="Systray Application" packages="net.i2p.apps.systray" />
|
||||||
<sourcepath>
|
<sourcepath>
|
||||||
<pathelement location="core/java/src" />
|
<pathelement location="core/java/src" />
|
||||||
@ -412,10 +410,16 @@
|
|||||||
<pathelement location="apps/BOB/src" />
|
<pathelement location="apps/BOB/src" />
|
||||||
<pathelement location="apps/susidns/src/java/src" />
|
<pathelement location="apps/susidns/src/java/src" />
|
||||||
<pathelement location="apps/susimail/src/src" />
|
<pathelement location="apps/susimail/src/src" />
|
||||||
|
<pathelement location="apps/jetty/java/src" />
|
||||||
</sourcepath>
|
</sourcepath>
|
||||||
<classpath>
|
<classpath>
|
||||||
<pathelement location="apps/jetty/jettylib/org.mortbay.jetty.jar" />
|
<pathelement location="apps/jetty/jettylib/org.mortbay.jetty.jar" />
|
||||||
<pathelement location="apps/jetty/jettylib/javax.servlet.jar" />
|
<pathelement location="apps/jetty/jettylib/javax.servlet.jar" />
|
||||||
|
<pathelement location="apps/jetty/jettylib/jetty-sslengine.jar" />
|
||||||
|
<pathelement location="apps/jetty/jettylib/jetty-start.jar" />
|
||||||
|
<pathelement location="apps/jetty/jettylib/jetty-threadpool.jar" />
|
||||||
|
<pathelement location="apps/jetty/jettylib/jetty-util.jar" />
|
||||||
|
<pathelement location="apps/jetty/jettylib/jsp-api.jar" />
|
||||||
<pathelement location="apps/systray/java/lib/systray4j.jar" />
|
<pathelement location="apps/systray/java/lib/systray4j.jar" />
|
||||||
<pathelement location="apps/jrobin/jrobin-1.5.9.1.jar" />
|
<pathelement location="apps/jrobin/jrobin-1.5.9.1.jar" />
|
||||||
<pathelement location="installer/lib/wrapper/all/wrapper.jar" />
|
<pathelement location="installer/lib/wrapper/all/wrapper.jar" />
|
||||||
@ -670,14 +674,12 @@
|
|||||||
</delete>
|
</delete>
|
||||||
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
|
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
|
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
<!-- all jetty stuff -->
|
||||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
<copy todir="pkg-temp/lib" >
|
||||||
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
|
<fileset dir="build" includes="commons*.jar jasper*.jar javax*.jar jetty*.jar jsp*.jar org.mortbay.jetty.jar" />
|
||||||
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
|
</copy>
|
||||||
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
|
|
||||||
<copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
|
<copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/streaming.jar" todir="pkg-temp/lib/" />
|
<copy file="build/streaming.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
|
||||||
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/desktopgui.jar" todir="pkg-temp/lib/" />
|
<copy file="build/desktopgui.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
<copy file="build/routerconsole.jar" todir="pkg-temp/lib/" />
|
||||||
@ -724,20 +726,13 @@
|
|||||||
<copy file="installer/resources/uninstall.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/uninstall.ico" todir="pkg-temp/docs/" />
|
||||||
<!-- Eepsite stuff here -->
|
<!-- Eepsite stuff here -->
|
||||||
<mkdir dir="pkg-temp/eepsite" />
|
<mkdir dir="pkg-temp/eepsite" />
|
||||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
<copy todir="pkg-temp/eepsite/" >
|
||||||
<mkdir dir="pkg-temp/eepsite/logs" />
|
<fileset dir="installer/resources/eepsite/" />
|
||||||
<mkdir dir="pkg-temp/eepsite/cgi-bin" />
|
|
||||||
<mkdir dir="pkg-temp/eepsite/docroot" />
|
|
||||||
<mkdir dir="pkg-temp/eepsite/docroot/help" />
|
|
||||||
<mkdir dir="pkg-temp/eepsite/docroot/help/lib" />
|
|
||||||
<copy todir="pkg-temp/eepsite/docroot/" >
|
|
||||||
<fileset dir="installer/resources/eepsite.help/" />
|
|
||||||
</copy>
|
</copy>
|
||||||
<copy todir="pkg-temp/eepsite/docroot/help/lib/" >
|
<copy todir="pkg-temp/eepsite/docroot/help/lib/" >
|
||||||
<fileset dir="installer/resources/icons/flags/" includes="cn.png de.png es.png fr.png ir.png it.png jp.png nl.png ru.png se.png us.png" />
|
<fileset dir="installer/resources/icons/flags/" includes="cn.png de.png es.png fr.png ir.png it.png jp.png nl.png ru.png se.png us.png" />
|
||||||
</copy>
|
</copy>
|
||||||
<copy file="installer/resources/themes/console/images/favicon.ico" tofile="pkg-temp/eepsite/docroot/favicon.ico" />
|
<copy file="installer/resources/themes/console/images/favicon.ico" tofile="pkg-temp/eepsite/docroot/favicon.ico" />
|
||||||
<copy file="installer/resources/jetty.xml" tofile="pkg-temp/eepsite/jetty.xml" />
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="preplicenses">
|
<target name="preplicenses">
|
||||||
@ -931,14 +926,18 @@
|
|||||||
</copy>
|
</copy>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<!-- All jetty jars required for update.
|
||||||
|
We don't need commons-el or commons-logging, they haven't changed.
|
||||||
|
TODO do we need to bother updating jasper?
|
||||||
|
TODO where is JMX? We don't need it I hope.
|
||||||
|
-->
|
||||||
<target name="prepjupdate" depends="prepupdate, buildWEB">
|
<target name="prepjupdate" depends="prepupdate, buildWEB">
|
||||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
<copy todir="pkg-temp" >
|
||||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
<fileset dir="build/lib" includes="jasper*.jar javax*.jar jetty*.jar jsp*.jar org.mortbay.jetty.jar" />
|
||||||
<copy file="build/commons-logging.jar" todir="pkg-temp/lib/" />
|
</copy>
|
||||||
<copy file="build/commons-el.jar" todir="pkg-temp/lib/" />
|
|
||||||
<copy file="build/javax.servlet.jar" todir="pkg-temp/lib/" />
|
|
||||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<!-- just our jetty 5 fixes, not for jetty 6 -->
|
||||||
<target name="prepjupdatefixes" depends="prepupdate, buildWEB">
|
<target name="prepjupdatefixes" depends="prepupdate, buildWEB">
|
||||||
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
<copy file="build/org.mortbay.jetty.jar" todir="pkg-temp/lib/" />
|
||||||
</target>
|
</target>
|
||||||
|
@ -40,7 +40,7 @@ clientApp.2.args=i2ptunnel.config
|
|||||||
clientApp.2.startOnLoad=true
|
clientApp.2.startOnLoad=true
|
||||||
|
|
||||||
# run our own eepsite with a seperate jetty instance
|
# run our own eepsite with a seperate jetty instance
|
||||||
clientApp.3.main=org.mortbay.jetty.Server
|
clientApp.3.main=org.mortbay.start.Main
|
||||||
clientApp.3.name=I2P webserver (eepsite)
|
clientApp.3.name=I2P webserver (eepsite)
|
||||||
clientApp.3.args="eepsite/jetty.xml"
|
clientApp.3.args="eepsite/jetty.xml"
|
||||||
clientApp.3.delay=30
|
clientApp.3.delay=30
|
||||||
|
25
installer/resources/eepsite/contexts/base-context.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Configure a custom context for the eepsite.
|
||||||
|
|
||||||
|
This context contains only a ServletHandler with a default servlet
|
||||||
|
to serve static html files and images.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Configure class="org.mortbay.jetty.handler.ContextHandler">
|
||||||
|
<Set name="contextPath">/</Set>
|
||||||
|
<Set name="resourceBase">./eepsite/docroot/</Set>
|
||||||
|
<Set name="handler">
|
||||||
|
<New class="org.mortbay.jetty.handler.ResourceHandler">
|
||||||
|
<Set name="welcomeFiles">
|
||||||
|
<Array type="String">
|
||||||
|
<Item>index.html</Item>
|
||||||
|
</Array>
|
||||||
|
</Set>
|
||||||
|
<Set name="cacheControl">max-age=3600,public</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</Configure>
|
||||||
|
|
33
installer/resources/eepsite/contexts/cgi-context.xml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Configure a custom context for the eepsite.
|
||||||
|
|
||||||
|
* CGI Servlet.
|
||||||
|
*
|
||||||
|
* The cgi bin directory can be set with the "cgibinResourceBase" init parameter
|
||||||
|
* or it will default to the resource base of the context.
|
||||||
|
*
|
||||||
|
* The "commandPrefix" init parameter may be used to set a prefix to all
|
||||||
|
* commands passed to exec. This can be used on systems that need assistance to
|
||||||
|
* execute a particular file type. For example on windows this can be set to
|
||||||
|
* "perl" so that perl scripts are executed.
|
||||||
|
*
|
||||||
|
* The "Path" init param is passed to the exec environment as PATH. Note: Must
|
||||||
|
* be run unpacked somewhere in the filesystem.
|
||||||
|
*
|
||||||
|
* Any initParameter that starts with ENV_ is used to set an environment
|
||||||
|
* variable with the name stripped of the leading ENV_ and using the init
|
||||||
|
* parameter value.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Configure class="org.mortbay.jetty.handler.ContextHandler">
|
||||||
|
<Set name="contextPath">/cgi-bin</Set>
|
||||||
|
<Set name="handler">
|
||||||
|
<New class="org.mortbay.servlet.CGI">
|
||||||
|
<Set name="cgibinResourceBase">./eepsite/cgi-bin/</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</Configure>
|
||||||
|
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 237 B After Width: | Height: | Size: 237 B |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
21
installer/resources/eepsite/etc/realm.properties
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# This file defines users passwords and roles for a HashUserRealm
|
||||||
|
#
|
||||||
|
# The format is
|
||||||
|
# <username>: <password>[,<rolename> ...]
|
||||||
|
#
|
||||||
|
# Passwords may be clear text, obfuscated or checksummed. The class
|
||||||
|
# org.mortbay.util.Password should be used to generate obfuscated
|
||||||
|
# passwords or password checksums
|
||||||
|
#
|
||||||
|
# If DIGEST Authentication is used, the password must be in a recoverable
|
||||||
|
# format, either plain text or OBF:.
|
||||||
|
#
|
||||||
|
jetty: MD5:164c88b302622e17050af52c89945d44,user
|
||||||
|
admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
|
||||||
|
other: OBF:1xmk1w261u9r1w1c1xmq
|
||||||
|
plain: plain
|
||||||
|
user: password
|
||||||
|
|
||||||
|
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
|
||||||
|
digest: MD5:6e120743ad67abfbc385bc2bb754e297
|
269
installer/resources/eepsite/jetty.xml
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
||||||
|
|
||||||
|
<!-- ========================================================================= -->
|
||||||
|
<!-- This file configures the Jetty server. -->
|
||||||
|
<!-- All changes require a restart of I2P. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Commonly changed settings: -->
|
||||||
|
<!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section -->
|
||||||
|
<!-- to access the server directly (bypassing i2p) -->
|
||||||
|
<!-- from other computers. The included version of Jetty has -->
|
||||||
|
<!-- been patched to allow IPv6 addresses as well, -->
|
||||||
|
<!-- enclosed in brackets e.g. [::1] -->
|
||||||
|
<!-- * port: Default 7658 in the addListener section -->
|
||||||
|
<!-- * docroot: Change the ResourceBase in the addContext section -->
|
||||||
|
<!-- to serve files from a different location. -->
|
||||||
|
<!-- * threads: Raise MinThreads and/or MaxThreads in the addListener section -->
|
||||||
|
<!-- if you have a high-traffic site and get a lot of warnings. -->
|
||||||
|
<!-- * Uncomment the addWebApplications section to use to enable -->
|
||||||
|
<!-- war files placed in the webapps/ dir. -->
|
||||||
|
<!-- * Uncomment the line to allow Jetty to follow symlinks -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- I2P uses Jetty 5.1.15. We have no plans to upgrade to Jetty 6, due to -->
|
||||||
|
<!-- the significant changes in the API. If you need web server features not -->
|
||||||
|
<!-- found in Jetty 5, you may install and run Jetty 6 in a different JVM, -->
|
||||||
|
<!-- or run any other web server such as Apache. If you do run another -->
|
||||||
|
<!-- web server instead, be sure and disable the Jetty 5 server for your -->
|
||||||
|
<!-- eepsite on http://127.0.0.1:7657/configclients.jsp . -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Jetty errors and warnings will appear in wrapper.log, check there -->
|
||||||
|
<!-- to diagnose problems. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Note that the XML encoding for this file is UTF-8. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- If you have a 'split' directory installation, with configuration -->
|
||||||
|
<!-- files in ~/.i2p (Linux) or %APPDATA%\I2P (Windows), be sure to -->
|
||||||
|
<!-- edit the file in the configuration directory, NOT the install directory. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- ========================================================================= -->
|
||||||
|
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
<!-- Configure the Jetty Server -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Documentation of this file format can be found at: -->
|
||||||
|
<!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.mortbay.jetty.Server">
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Server Thread Pool -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Set name="ThreadPool">
|
||||||
|
|
||||||
|
<!-- If you don't have threadpool
|
||||||
|
<New class="org.mortbay.thread.QueuedThreadPool">
|
||||||
|
<Set name="minThreads">1</Set>
|
||||||
|
<Set name="maxThreads">16</Set>
|
||||||
|
<Set name="lowThreads">2</Set>
|
||||||
|
</New>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Optional Java 5 bounded threadpool with job queue
|
||||||
|
<New class="org.mortbay.thread.concurrent.ThreadPool">
|
||||||
|
<Set name="corePoolSize">1</Set>
|
||||||
|
<Set name="maximumPoolSize">16</Set>
|
||||||
|
</New>
|
||||||
|
-->
|
||||||
|
</Set>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Set connectors -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- One of each type! -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
|
||||||
|
<!-- Use this connector for many frequently idle connections
|
||||||
|
and for threadless continuations.
|
||||||
|
-->
|
||||||
|
<Call name="addConnector">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.mortbay.jetty.nio.SelectChannelConnector">
|
||||||
|
<Set name="host">127.0.0.1</Set>
|
||||||
|
<Set name="port">7658</Set>
|
||||||
|
<Set name="maxIdleTime">60000</Set>
|
||||||
|
<Set name="Acceptors">2</Set>
|
||||||
|
<Set name="statsOn">false</Set>
|
||||||
|
<Set name="confidentialPort">8443</Set>
|
||||||
|
<Set name="lowResourcesConnections">5000</Set>
|
||||||
|
<Set name="lowResourcesMaxIdleTime">5000</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
|
||||||
|
<!-- Use this connector if NIO is not available.
|
||||||
|
<Call name="addConnector">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.mortbay.jetty.bio.SocketConnector">
|
||||||
|
<Set name="port">7658</Set>
|
||||||
|
<Set name="maxIdleTime">50000</Set>
|
||||||
|
<Set name="lowResourceMaxIdleTime">1500</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
<!-- To add a HTTPS SSL listener -->
|
||||||
|
<!-- see jetty-ssl.xml to add an ssl connector. use -->
|
||||||
|
<!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
<!-- Add a HTTPS SSL listener on port 8443 -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- In the unlikely event you would want SSL support for your eepsite. -->
|
||||||
|
<!-- You would need to generate a selfsigned certificate in a keystore -->
|
||||||
|
<!-- in ~/.i2p/eepsite/keystore.ks, for example with the command line: -->
|
||||||
|
<!--
|
||||||
|
keytool -genkey -storetype JKS -keystore ~/.i2p/eepsite/keystore.ks -storepass changeit -alias console -dname CN=xyz123.eepsite.i2p.net,OU=Eepsite,O=I2P Anonymous Network,L=XX,ST=XX,C=XX -validity 3650 -keyalg DSA -keysize 1024 -keypass myKeyPassword
|
||||||
|
-->
|
||||||
|
<!-- Change the CN and key password in the example, of course. -->
|
||||||
|
<!-- You wouldn't want to open this up to the regular internet, -->
|
||||||
|
<!-- would you?? Untested and not recommended. -->
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
<!-- To allow Jetty to be started from xinetd -->
|
||||||
|
<!-- mixin jetty-xinetd.xml: -->
|
||||||
|
<!-- java -jar start.jar etc/jetty.xml etc/jetty-xinetd.xml -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- See jetty-xinetd.xml for further instructions. -->
|
||||||
|
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Set up global session ID manager -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!--
|
||||||
|
<Set name="sessionIdManager">
|
||||||
|
<New class="org.mortbay.jetty.servlet.HashSessionIdManager">
|
||||||
|
<Set name="workerName">node1</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Set handler Collection Structure -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Set name="handler">
|
||||||
|
<New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
|
||||||
|
<Set name="handlers">
|
||||||
|
<Array type="org.mortbay.jetty.Handler">
|
||||||
|
<Item>
|
||||||
|
<New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>
|
||||||
|
</Item>
|
||||||
|
</Array>
|
||||||
|
</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Configure the context deployer -->
|
||||||
|
<!-- A context deployer will deploy contexts described in -->
|
||||||
|
<!-- configuration files discovered in a directory. -->
|
||||||
|
<!-- The configuration directory can be scanned for hot -->
|
||||||
|
<!-- deployments at the configured scanInterval. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- This deployer is configured to deploy contexts configured -->
|
||||||
|
<!-- in the $JETTY_HOME/contexts directory -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Call name="addLifeCycle">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.mortbay.jetty.deployer.ContextDeployer">
|
||||||
|
<Set name="contexts"><Ref id="Contexts"/></Set>
|
||||||
|
<Set name="configurationDir">./eepsite/contexts</Set>
|
||||||
|
<Set name="scanInterval">0</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Configure the webapp deployer. -->
|
||||||
|
<!-- A webapp deployer will deploy standard webapps discovered -->
|
||||||
|
<!-- in a directory at startup, without the need for additional -->
|
||||||
|
<!-- configuration files. It does not support hot deploy or -->
|
||||||
|
<!-- non standard contexts (see ContextDeployer above). -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- This deployer is configured to deploy webapps from the -->
|
||||||
|
<!-- $JETTY_HOME/webapps directory -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Normally only one type of deployer need be used. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- UNCOMMENT TO ACTIVATE
|
||||||
|
<Call name="addLifeCycle">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.mortbay.jetty.deployer.WebAppDeployer">
|
||||||
|
<Set name="contexts"><Ref id="Contexts"/></Set>
|
||||||
|
<Set name="webAppDir">./eepsite/webapps</Set>
|
||||||
|
<Set name="parentLoaderPriority">false</Set>
|
||||||
|
<Set name="extract">true</Set>
|
||||||
|
<Set name="allowDuplicates">false</Set>
|
||||||
|
<Set name="defaultsDescriptor">./eepsite/etc/webdefault.xml</Set>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Configure Authentication Realms -->
|
||||||
|
<!-- Realms may be configured for the entire server here, or -->
|
||||||
|
<!-- they can be configured for a specific web app in a context -->
|
||||||
|
<!-- configuration (see $(jetty.home)/contexts/test.xml for an -->
|
||||||
|
<!-- example). -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- UNCOMMENT TO ACTIVATE
|
||||||
|
<Set name="UserRealms">
|
||||||
|
<Array type="org.mortbay.jetty.security.UserRealm">
|
||||||
|
<Item>
|
||||||
|
<New class="org.mortbay.jetty.security.HashUserRealm">
|
||||||
|
<Set name="name">Test Realm</Set>
|
||||||
|
<Set name="config">./eepsite/etc/realm.properties</Set>
|
||||||
|
<Set name="refreshInterval">0</Set>
|
||||||
|
</New>
|
||||||
|
</Item>
|
||||||
|
</Array>
|
||||||
|
</Set>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- Configure Request Log -->
|
||||||
|
<!-- Request logs may be configured for the entire server here, -->
|
||||||
|
<!-- or they can be configured for a specific web app in a -->
|
||||||
|
<!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
|
||||||
|
<!-- for an example). -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Ref id="RequestLog">
|
||||||
|
<Set name="requestLog">
|
||||||
|
<New id="RequestLogImpl" class="org.mortbay.http.I2PRequestLog">
|
||||||
|
<Set name="filename">./eepsite/logs/yyyy_mm_dd.request.log</Set>
|
||||||
|
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
|
||||||
|
<Set name="retainDays">90</Set>
|
||||||
|
<Set name="append">true</Set>
|
||||||
|
<Set name="extended">false</Set>
|
||||||
|
<Set name="logCookies">false</Set>
|
||||||
|
<Set name="LogTimeZone">GMT</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</Ref>
|
||||||
|
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<!-- extra options -->
|
||||||
|
<!-- =========================================================== -->
|
||||||
|
<Set name="stopAtShutdown">true</Set>
|
||||||
|
<Set name="sendServerVersion">false</Set>
|
||||||
|
<Set name="sendDateHeader">true</Set>
|
||||||
|
<Set name="gracefulShutdown">1000</Set>
|
||||||
|
|
||||||
|
</Configure>
|
@ -1,238 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
|
||||||
|
|
||||||
<!-- ========================================================================= -->
|
|
||||||
<!-- This file configures the Jetty server. -->
|
|
||||||
<!-- All changes require a restart of I2P. -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- Commonly changed settings: -->
|
|
||||||
<!-- * host: Change 127.0.0.1 to 0.0.0.0 in the addListener section -->
|
|
||||||
<!-- to access the server directly (bypassing i2p) -->
|
|
||||||
<!-- from other computers. The included version of Jetty has -->
|
|
||||||
<!-- been patched to allow IPv6 addresses as well, -->
|
|
||||||
<!-- enclosed in brackets e.g. [::1] -->
|
|
||||||
<!-- * port: Default 7658 in the addListener section -->
|
|
||||||
<!-- * docroot: Change the ResourceBase in the addContext section -->
|
|
||||||
<!-- to serve files from a different location. -->
|
|
||||||
<!-- * threads: Raise MinThreads and/or MaxThreads in the addListener section -->
|
|
||||||
<!-- if you have a high-traffic site and get a lot of warnings. -->
|
|
||||||
<!-- * Uncomment the addWebApplications section to use to enable -->
|
|
||||||
<!-- war files placed in the webapps/ dir. -->
|
|
||||||
<!-- * Uncomment the line to allow Jetty to follow symlinks -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- I2P uses Jetty 5.1.15. We have no plans to upgrade to Jetty 6, due to -->
|
|
||||||
<!-- the significant changes in the API. If you need web server features not -->
|
|
||||||
<!-- found in Jetty 5, you may install and run Jetty 6 in a different JVM, -->
|
|
||||||
<!-- or run any other web server such as Apache. If you do run another -->
|
|
||||||
<!-- web server instead, be sure and disable the Jetty 5 server for your -->
|
|
||||||
<!-- eepsite on http://127.0.0.1:7657/configclients.jsp . -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- Jetty errors and warnings will appear in wrapper.log, check there -->
|
|
||||||
<!-- to diagnose problems. -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- Note that the XML encoding for this file is UTF-8. -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- If you have a 'split' directory installation, with configuration -->
|
|
||||||
<!-- files in ~/.i2p (Linux) or %APPDATA%\I2P (Windows), be sure to -->
|
|
||||||
<!-- edit the file in the configuration directory, NOT the install directory. -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- ========================================================================= -->
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Configure the Jetty Server -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<Configure class="org.mortbay.jetty.Server">
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Configure the Request Listeners -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- Add and configure a HTTP listener to port 8080 -->
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<Call name="addListener">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.http.SocketListener">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.util.InetAddrPort">
|
|
||||||
<Set name="host">127.0.0.1</Set>
|
|
||||||
<Set name="port">7658</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
<Set name="MinThreads">1</Set>
|
|
||||||
<Set name="MaxThreads">16</Set>
|
|
||||||
<Set name="MaxIdleTimeMs">60000</Set>
|
|
||||||
<Set name="LowResourcePersistTimeMs">1000</Set>
|
|
||||||
<Set name="ConfidentialPort">8443</Set>
|
|
||||||
<Set name="IntegralPort">8443</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- Add a HTTPS SSL listener on port 8443 -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- In the unlikely event you would want SSL support for your eepsite. -->
|
|
||||||
<!-- You would need to generate a selfsigned certificate in a keystore -->
|
|
||||||
<!-- in ~/.i2p/eepsite/keystore.ks, for example with the command line: -->
|
|
||||||
<!--
|
|
||||||
keytool -genkey -storetype JKS -keystore ~/.i2p/eepsite/keystore.ks -storepass changeit -alias console -dname CN=xyz123.eepsite.i2p.net,OU=Eepsite,O=I2P Anonymous Network,L=XX,ST=XX,C=XX -validity 3650 -keyalg DSA -keysize 1024 -keypass myKeyPassword
|
|
||||||
-->
|
|
||||||
<!-- Change the CN and key password in the example, of course. -->
|
|
||||||
<!-- You wouldn't want to open this up to the regular internet, -->
|
|
||||||
<!-- would you?? Untested and not recommended. -->
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- UNCOMMENT TO ACTIVATE
|
|
||||||
<Call name="addListener">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.http.SslListener">
|
|
||||||
<Set name="Port">8443</Set>
|
|
||||||
<Set name="PoolName">main</Set>
|
|
||||||
<Set name="Keystore">./eepsite/keystore.ks</Set>
|
|
||||||
<Set name="Password">changeit</Set>
|
|
||||||
<Set name="KeyPassword">myKeyPassword</Set>
|
|
||||||
<Set name="NonPersistentUserAgent">MSIE 5</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- Add a AJP13 listener on port 8009 -->
|
|
||||||
<!-- This protocol can be used with mod_jk in apache, IIS etc. -->
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- UNCOMMENT TO ACTIVATE
|
|
||||||
<Call name="addListener">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.http.ajp.AJP13Listener">
|
|
||||||
<Set name="PoolName">ajp</Set>
|
|
||||||
<Set name="Port">8009</Set>
|
|
||||||
<Set name="MinThreads">3</Set>
|
|
||||||
<Set name="MaxThreads">20</Set>
|
|
||||||
<Set name="MaxIdleTimeMs">0</Set>
|
|
||||||
<Set name="confidentialPort">443</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Uncomment this to allow Jetty to follow symlinks -->
|
|
||||||
<!-- Jetty declares this to be a security risk, use with care -->
|
|
||||||
<!-- See also http://docs.codehaus.org/display/JETTY/How+to+enable+serving+aliased+files -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- UNCOMMENT TO ACTIVATE
|
|
||||||
<Set name="checkAliases" class="org.mortbay.util.FileResource" type="boolean">false</Set>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Configure the Contexts -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- Add a all web application within the webapps directory. -->
|
|
||||||
<!-- + No virtual host specified -->
|
|
||||||
<!-- + Look in the webapps directory relative to jetty.home or . -->
|
|
||||||
<!-- + Use the default webdefault.xml in jetty's install -->
|
|
||||||
<!-- + Upack the war file -->
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<Set name="rootWebApp">root</Set>
|
|
||||||
<!-- UNCOMMENT TO ACTIVATE
|
|
||||||
<Call name="addWebApplications">
|
|
||||||
<Arg></Arg>
|
|
||||||
<Arg>./eepsite/webapps/</Arg>
|
|
||||||
<Arg></Arg>
|
|
||||||
<Arg type="boolean">true</Arg>
|
|
||||||
</Call>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- Add and configure a specific web application -->
|
|
||||||
<!-- + Set Unpack WAR files -->
|
|
||||||
<!-- + Set Default Descriptor. Resource, file or URL -->
|
|
||||||
<!-- + Set Virtual Hosts. A Null host or empty array means all hosts -->
|
|
||||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
|
||||||
<!-- UNCOMMENT TO ACTIVATE
|
|
||||||
<Call name="addWebApplication">
|
|
||||||
<Arg>/context</Arg>
|
|
||||||
<Arg>./webapps/root</Arg>
|
|
||||||
|
|
||||||
<Set name="extractWAR">false</Set>
|
|
||||||
|
|
||||||
<Set name="defaultsDescriptor">org/mortbay/jetty/servlet/webdefault.xml</Set>
|
|
||||||
|
|
||||||
<Set name="virtualHosts">
|
|
||||||
<Array type="java.lang.String">
|
|
||||||
<Item></Item>
|
|
||||||
<Item>127.0.0.1</Item>
|
|
||||||
<Item>localhost</Item>
|
|
||||||
<Item>www.acme.com</Item>
|
|
||||||
</Array>
|
|
||||||
</Set>
|
|
||||||
</Call>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<Call name="addContext">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.http.HttpContext">
|
|
||||||
<Set name="contextPath">/</Set>
|
|
||||||
<Set name="resourceBase">./eepsite/docroot</Set>
|
|
||||||
<Call name="addHandler">
|
|
||||||
<Arg>
|
|
||||||
<New class="org.mortbay.http.handler.ResourceHandler">
|
|
||||||
<Set name="redirectWelcome">FALSE</Set>
|
|
||||||
<!-- disable TRACE and OPTIONS ref: http://osdir.com/ml/java.jetty.support/2003-11/msg00014.html -->
|
|
||||||
<Set name="AllowedMethods">
|
|
||||||
<Array type="String">
|
|
||||||
<Item>GET</Item>
|
|
||||||
<Item>HEAD</Item>
|
|
||||||
<Item>POST</Item>
|
|
||||||
</Array>
|
|
||||||
</Set>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
</New>
|
|
||||||
</Arg>
|
|
||||||
</Call>
|
|
||||||
|
|
||||||
<Call name="addContext">
|
|
||||||
<Arg>/cgi-bin/*</Arg>
|
|
||||||
<Set name="ResourceBase">./eepsite/cgi-bin</Set>
|
|
||||||
<Call name="addServlet">
|
|
||||||
<Arg>Common Gateway Interface</Arg>
|
|
||||||
<Arg>/</Arg>
|
|
||||||
<Arg>org.mortbay.servlet.CGI</Arg>
|
|
||||||
<Put name="Path">/usr/local/bin:/usr/ucb:/bin:/usr/bin</Put>
|
|
||||||
</Call>
|
|
||||||
</Call>
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Configure the Request Log -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<Set name="RequestLog">
|
|
||||||
<New class="org.mortbay.http.I2PRequestLog">
|
|
||||||
<Arg>./eepsite/logs/yyyy_mm_dd.request.log</Arg>
|
|
||||||
<Set name="retainDays">90</Set>
|
|
||||||
<Set name="append">true</Set>
|
|
||||||
<Set name="extended">false</Set>
|
|
||||||
<Set name="buffered">false</Set>
|
|
||||||
<Set name="LogTimeZone">GMT</Set>
|
|
||||||
</New>
|
|
||||||
</Set>
|
|
||||||
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<!-- Configure the Other Server Options -->
|
|
||||||
<!-- =============================================================== -->
|
|
||||||
<Set name="requestsPerGC">2000</Set>
|
|
||||||
<!-- defaults to false, requires access through jconsole?
|
|
||||||
<Set name="statsOn">false</Set>
|
|
||||||
-->
|
|
||||||
|
|
||||||
</Configure>
|
|
@ -147,7 +147,9 @@ public class WorkingDir {
|
|||||||
System.err.println("Setting up new user directory " + rv);
|
System.err.println("Setting up new user directory " + rv);
|
||||||
boolean success = migrate(MIGRATE_BASE, oldDirf, dirf);
|
boolean success = migrate(MIGRATE_BASE, oldDirf, dirf);
|
||||||
// this one must be after MIGRATE_BASE
|
// this one must be after MIGRATE_BASE
|
||||||
success &= migrateJettyXml(oldDirf, dirf);
|
success &= migrateJettyXml(oldDirf, dirf, "jetty.xml");
|
||||||
|
success &= migrateJettyXml(oldDirf, dirf, "contexts/base-context.xml");
|
||||||
|
success &= migrateJettyXml(oldDirf, dirf, "contexts/cgi-context.xml");
|
||||||
success &= migrateClientsConfig(oldDirf, dirf);
|
success &= migrateClientsConfig(oldDirf, dirf);
|
||||||
// for later news.xml updates (we don't copy initialNews.xml over anymore)
|
// for later news.xml updates (we don't copy initialNews.xml over anymore)
|
||||||
success &= (new SecureDirectory(dirf, "docs")).mkdir();
|
success &= (new SecureDirectory(dirf, "docs")).mkdir();
|
||||||
@ -258,11 +260,11 @@ public class WorkingDir {
|
|||||||
* It was already copied over once in migrate(), throw that out and
|
* It was already copied over once in migrate(), throw that out and
|
||||||
* do it again with modifications.
|
* do it again with modifications.
|
||||||
*/
|
*/
|
||||||
private static boolean migrateJettyXml(File olddir, File todir) {
|
private static boolean migrateJettyXml(File olddir, File todir, String filename) {
|
||||||
File eepsite1 = new File(olddir, "eepsite");
|
File eepsite1 = new File(olddir, "eepsite");
|
||||||
File oldFile = new File(eepsite1, "jetty.xml");
|
File oldFile = new File(eepsite1, filename);
|
||||||
File eepsite2 = new File(todir, "eepsite");
|
File eepsite2 = new File(todir, "eepsite");
|
||||||
File newFile = new File(eepsite2, "jetty.xml");
|
File newFile = new File(eepsite2, filename);
|
||||||
FileInputStream in = null;
|
FileInputStream in = null;
|
||||||
PrintWriter out = null;
|
PrintWriter out = null;
|
||||||
try {
|
try {
|
||||||
@ -276,11 +278,11 @@ public class WorkingDir {
|
|||||||
out.println(s);
|
out.println(s);
|
||||||
}
|
}
|
||||||
out.println("<!-- Modified by I2P User dir migration script -->");
|
out.println("<!-- Modified by I2P User dir migration script -->");
|
||||||
System.err.println("Copied jetty.xml with modifications");
|
System.err.println("Copied " + filename + " with modifications");
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
System.err.println("FAILED copy jetty.xml");
|
System.err.println("FAILED copy " + filename);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|