propagate from branch 'i2p.i2p' (head 5737078c5993e2fcf73520cc610a71125b12520b)

to branch 'i2p.i2p.zzz.jetty7' (head a93a47d79b1db119ec8c62b46a4a4e226043bd17)
This commit is contained in:
zzz
2013-04-07 13:20:34 +00:00
52 changed files with 1940 additions and 600 deletions

View File

@@ -19,6 +19,7 @@
<pathelement location="../../ministreaming/java/build/obj" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/jetty-servlet.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
</classpath>
</depend>
@@ -38,7 +39,7 @@
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
includeAntRuntime="false"
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" >
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>
@@ -103,9 +104,11 @@
<copy todir="build/icons/.icons" >
<fileset dir="../icons/" />
</copy>
<!-- mime.properties must be in with the classes -->
<copy file="../mime.properties" todir="build/obj/org/klomp/snark/web" />
<war destfile="../i2psnark.war" webxml="../web.xml" >
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
<classes dir="./build/obj" includes="**/web/*.class" />
<classes dir="./build/obj" includes="**/web/*" />
<fileset dir="build/icons/" />
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />

View File

@@ -49,6 +49,7 @@ import org.klomp.snark.dht.KRPC;
public class I2PSnarkUtil {
private final I2PAppContext _context;
private final Log _log;
private final String _baseName;
private boolean _shouldProxy;
private String _proxyHost;
@@ -82,8 +83,17 @@ public class I2PSnarkUtil {
public static final boolean DEFAULT_USE_DHT = true;
public I2PSnarkUtil(I2PAppContext ctx) {
this(ctx, "i2psnark");
}
/**
* @param baseName generally "i2psnark"
* @since Jetty 7
*/
public I2PSnarkUtil(I2PAppContext ctx, String baseName) {
_context = ctx;
_log = _context.logManager().getLog(Snark.class);
_baseName = baseName;
_opts = new HashMap();
//setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", 7654, null);
@@ -99,7 +109,7 @@ public class I2PSnarkUtil {
// This is used for both announce replies and .torrent file downloads,
// so it must be available even if not connected to I2CP.
// so much for multiple instances
_tmpDir = new SecureDirectory(ctx.getTempDir(), "i2psnark");
_tmpDir = new SecureDirectory(ctx.getTempDir(), baseName);
FileUtil.rmdir(_tmpDir, false);
_tmpDir.mkdirs();
}
@@ -253,7 +263,7 @@ public class I2PSnarkUtil {
_connecting = false;
}
if (_shouldUseDHT && _manager != null && _dht == null)
_dht = new KRPC(_context, _manager.getSession());
_dht = new KRPC(_context, _baseName, _manager.getSession());
return (_manager != null);
}
@@ -588,7 +598,7 @@ public class I2PSnarkUtil {
public synchronized void setUseDHT(boolean yes) {
_shouldUseDHT = yes;
if (yes && _manager != null && _dht == null) {
_dht = new KRPC(_context, _manager.getSession());
_dht = new KRPC(_context, _baseName, _manager.getSession());
} else if (!yes && _dht != null) {
_dht.stop();
_dht = null;

View File

@@ -57,6 +57,8 @@ public class SnarkManager implements CompleteListener {
private /* FIXME final FIXME */ File _configFile;
private Properties _config;
private final I2PAppContext _context;
private final String _contextPath;
private final String _contextName;
private final Log _log;
private final Queue<String> _messages;
private final I2PSnarkUtil _util;
@@ -82,7 +84,7 @@ public class SnarkManager implements CompleteListener {
public static final String PROP_META_PRIORITY_SUFFIX = ".priority";
public static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
private static final String CONFIG_FILE = "i2psnark.config";
private static final String CONFIG_FILE_SUFFIX = ".config";
public static final String PROP_FILES_PUBLIC = "i2psnark.filesPublic";
public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
public static final String DEFAULT_AUTO_START = "false";
@@ -128,17 +130,24 @@ public class SnarkManager implements CompleteListener {
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
public SnarkManager(I2PAppContext ctx) {
/**
* @param ctxPath generally "/i2psnark"
* @param ctxName generally "i2psnark"
*/
public SnarkManager(I2PAppContext ctx, String ctxPath, String ctxName) {
_snarks = new ConcurrentHashMap();
_magnets = new ConcurrentHashSet();
_addSnarkLock = new Object();
_context = ctx;
_contextPath = ctxPath;
_contextName = ctxName;
_log = _context.logManager().getLog(SnarkManager.class);
_messages = new LinkedBlockingQueue();
_util = new I2PSnarkUtil(_context);
_configFile = new File(CONFIG_FILE);
_util = new I2PSnarkUtil(_context, ctxName);
String cfile = ctxName + CONFIG_FILE_SUFFIX;
_configFile = new File(cfile);
if (!_configFile.isAbsolute())
_configFile = new File(_context.getConfigDir(), CONFIG_FILE);
_configFile = new File(_context.getConfigDir(), cfile);
_trackerMap = new ConcurrentHashMap(4);
loadConfig(null);
}
@@ -259,7 +268,7 @@ public class SnarkManager implements CompleteListener {
}
public File getDataDir() {
String dir = _config.getProperty(PROP_DIR, "i2psnark");
String dir = _config.getProperty(PROP_DIR, _contextName);
File f;
if (areFilesPublic())
f = new File(dir);
@@ -305,7 +314,7 @@ public class SnarkManager implements CompleteListener {
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
if (!_config.containsKey(PROP_DIR))
_config.setProperty(PROP_DIR, "i2psnark");
_config.setProperty(PROP_DIR, _contextName);
if (!_config.containsKey(PROP_AUTO_START))
_config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START);
if (!_config.containsKey(PROP_REFRESH_DELAY))
@@ -731,6 +740,11 @@ public class SnarkManager implements CompleteListener {
public Properties getConfig() { return _config; }
/** @since Jetty 7 */
public String getConfigFilename() {
return _configFile.getAbsolutePath();
}
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
public static final int MAX_FILES_PER_TORRENT = 512;
@@ -1445,7 +1459,7 @@ public class SnarkManager implements CompleteListener {
if (meta == null || storage == null)
return;
StringBuilder buf = new StringBuilder(256);
buf.append("<a href=\"/i2psnark/").append(storage.getBaseName());
buf.append("<a href=\"").append(_contextPath).append('/').append(storage.getBaseName());
if (meta.getFiles() != null)
buf.append('/');
buf.append("\">").append(storage.getBaseName()).append("</a>");

View File

@@ -152,12 +152,15 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
private static final long CLEAN_TIME = 63*1000;
private static final long EXPLORE_TIME = 877*1000;
private static final long BLACKLIST_CLEAN_TIME = 17*60*1000;
private static final String DHT_FILE = "i2psnark.dht.dat";
private static final String DHT_FILE_SUFFIX = ".dht.dat";
private static final int SEND_CRYPTO_TAGS = 8;
private static final int LOW_CRYPTO_TAGS = 4;
public KRPC (I2PAppContext ctx, I2PSession session) {
/**
* @param baseName generally "i2psnark"
*/
public KRPC (I2PAppContext ctx, String baseName, I2PSession session) {
_context = ctx;
_session = session;
_log = ctx.logManager().getLog(KRPC.class);
@@ -182,7 +185,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_myNID = new NID(_myID);
}
_myNodeInfo = new NodeInfo(_myNID, session.getMyDestination(), _qPort);
_dhtFile = new File(ctx.getConfigDir(), DHT_FILE);
_dhtFile = new File(ctx.getConfigDir(), baseName + DHT_FILE_SUFFIX);
_knownNodes = new DHTNodes(ctx, _myNID);
start();

View File

@@ -0,0 +1,550 @@
// ========================================================================
// 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.klomp.snark.web;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
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 javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
/* ------------------------------------------------------------ */
/**
* Based on DefaultServlet from Jetty 6.1.26, heavily simplified
* and modified to remove all dependencies on Jetty libs.
*
* Supports HEAD and GET only, for resources from the .war and local files.
* Supports files and resource only.
* Supports MIME types with local overrides and additions.
* Supports Last-Modified.
*
* Does not support directories or "welcome files".
* Does not support gzip.
* Does not support request ranges.
* Does not cache.
*
* HEAD and POST return 405.
* Directories return 403.
* Jar resources are sent with a long cache directive.
*
* ------------------------------------------------------------
*
* The default servlet.
* This servlet, normally mapped to /, provides the handling for static
* content, OPTION and TRACE methods for the context.
* The following initParameters are supported, these can be set either
* on the servlet itself or as ServletContext initParameters with a prefix
* of org.mortbay.jetty.servlet.Default. :
* <PRE>
*
* resourceBase Set to replace the context resource base
* warBase Path allowed for resource in war
*
* </PRE>
*
*
* @author Greg Wilkins (gregw)
* @author Nigel Canonizado
*
* @since Jetty 7
*/
class BasicServlet extends HttpServlet
{
protected final I2PAppContext _context;
protected final Log _log;
protected File _resourceBase;
private String _warBase;
private final MimeTypes _mimeTypes;
/** same as PeerState.PARTSIZE */
private static final int BUFSIZE = 16*1024;
private ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
private static final int WAR_CACHE_CONTROL_SECS = 24*60*60;
private static final int FILE_CACHE_CONTROL_SECS = 24*60*60;
public BasicServlet() {
super();
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(getClass());
_mimeTypes = new MimeTypes();
}
/* ------------------------------------------------------------ */
public void init(ServletConfig cfg) throws ServletException {
super.init(cfg);
String rb=getInitParameter("resourceBase");
if (rb!=null)
{
File f = new File(rb);
setResourceBase(f);
}
String wb = getInitParameter("warBase");
if (wb != null)
setWarBase(wb);
}
/**
* Files are served from here
*/
protected void setResourceBase(File base) throws UnavailableException {
if (!base.isDirectory())
throw new UnavailableException("Resource base does not exist: " + base);
_resourceBase = base;
if (_log.shouldLog(Log.INFO))
_log.info("Resource base is " + _resourceBase);
}
/**
* Only paths starting with this in the path are served
*/
protected void setWarBase(String base) {
if (!base.startsWith("/"))
base = '/' + base;
if (!base.endsWith("/"))
base = base + '/';
_warBase = base;
if (_log.shouldLog(Log.INFO))
_log.info("War base is " + _warBase);
}
/** get Resource to serve.
* Map a path to a resource. The default implementation calls
* HttpContext.getResource but derived servlets may provide
* their own mapping.
* @param pathInContext The path to find a resource for.
* @return The resource to serve or null if not existing
*/
public File getResource(String pathInContext)
{
if (_resourceBase==null)
return null;
File r = null;
if (!pathInContext.contains("..") &&
!pathInContext.endsWith("/")) {
File f = new File(_resourceBase, pathInContext);
if (f.exists())
r = f;
}
return r;
}
/** get Resource to serve.
* Map a path to a resource. The default implementation calls
* HttpContext.getResource but derived servlets may provide
* their own mapping.
* @param pathInContext The path to find a resource for.
* @return The resource to serve or null. Returns null for directories
*/
public HttpContent getContent(String pathInContext)
{
if (_resourceBase==null)
return null;
HttpContent r = null;
if (_warBase != null && pathInContext.startsWith(_warBase)) {
r = new JarContent(pathInContext);
} else if (!pathInContext.contains("..") &&
!pathInContext.endsWith("/")) {
File f = new File(_resourceBase, pathInContext);
// exists && !directory
if (f.isFile())
r = new FileContent(f);
}
return r;
}
/* ------------------------------------------------------------ */
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// always starts with a '/'
String servletpath = request.getServletPath();
String pathInfo=request.getPathInfo();
// ??? right??
String pathInContext = addPaths(servletpath, pathInfo);
// Find the resource and content
try {
HttpContent content = getContent(pathInContext);
// Handle resource
if (content == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not found: " + pathInContext);
response.sendError(404);
} else {
if (passConditionalHeaders(request, response, content)) {
if (_log.shouldLog(Log.INFO))
_log.info("Sending: " + content);
sendData(request, response, content);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not modified: " + content);
}
}
}
catch(IllegalArgumentException e)
{
if (_log.shouldLog(Log.WARN))
_log.warn("Error sending " + pathInContext, e);
if(!response.isCommitted())
response.sendError(500, e.getMessage());
}
catch(IOException e)
{
if (_log.shouldLog(Log.WARN))
// typical browser abort
//_log.warn("Error sending", e);
_log.warn("Error sending " + pathInContext + ": " + e);
throw e;
}
}
/* ------------------------------------------------------------ */
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
/* ------------------------------------------------------------ */
/** Check modification date headers.
* @return true to keep going, false if handled here
*/
protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, HttpContent content)
throws IOException
{
try
{
if (!request.getMethod().equals("HEAD") ) {
long ifmsl=request.getDateHeader("If-Modified-Since");
if (ifmsl!=-1)
{
if (content.getLastModified()/1000 <= ifmsl/1000)
{
response.reset();
response.setStatus(304);
response.flushBuffer();
return false;
}
}
}
}
catch(IllegalArgumentException iae)
{
if(!response.isCommitted())
response.sendError(400, iae.getMessage());
throw iae;
}
return true;
}
/* ------------------------------------------------------------ */
protected void sendData(HttpServletRequest request,
HttpServletResponse response,
HttpContent content)
throws IOException
{
InputStream in =null;
try {
in = content.getInputStream();
} catch (IOException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not found: " + content);
response.sendError(404);
return;
}
OutputStream out =null;
try {
out = response.getOutputStream();
} catch (IllegalStateException e) {
out = new WriterOutputStream(response.getWriter());
}
// Write content normally
long content_length = content.getContentLength();
writeHeaders(response,content,content_length);
if (content_length >= 0 && request.getMethod().equals("HEAD")) {
// if we know the content length, don't send it to be counted
if (_log.shouldLog(Log.INFO))
_log.info("HEAD: " + content);
} else {
// GET or unknown size for HEAD
copy(in, out);
}
return;
}
/* ------------------------------------------------------------ */
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
throws IOException
{
if (content.getContentType()!=null && response.getContentType()==null)
response.setContentType(content.getContentType());
long lml = content.getLastModified();
if (lml > 0)
response.setDateHeader("Last-Modified",lml);
if (count != -1)
{
if (count<Integer.MAX_VALUE)
response.setContentLength((int)count);
else
response.setHeader("Content-Length", Long.toString(count));
}
long ct = content.getCacheTime();
if (ct>=0)
response.setHeader("Cache-Control", "public, max-age=" + ct);
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* I2P additions below here */
/** from Jetty HttpContent.java */
public interface HttpContent
{
String getContentType();
long getLastModified();
/** in seconds */
int getCacheTime();
long getContentLength();
InputStream getInputStream() throws IOException;
}
private class FileContent implements HttpContent
{
private final File _file;
public FileContent(File file)
{
_file = file;
}
/* ------------------------------------------------------------ */
public String getContentType()
{
//return _mimeTypes.getMimeByExtension(_file.toString());
return getMimeType(_file.toString());
}
/* ------------------------------------------------------------ */
public long getLastModified()
{
return _file.lastModified();
}
public int getCacheTime()
{
return FILE_CACHE_CONTROL_SECS;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return _file.length();
}
/* ------------------------------------------------------------ */
public InputStream getInputStream() throws IOException
{
return new BufferedInputStream(new FileInputStream(_file));
}
@Override
public String toString() { return "File \"" + _file + '"'; }
}
private class JarContent implements HttpContent
{
private final String _path;
public JarContent(String path)
{
_path = path;
}
/* ------------------------------------------------------------ */
public String getContentType()
{
return getMimeType(_path);
}
/* ------------------------------------------------------------ */
public long getLastModified()
{
String cpath = getServletContext().getContextPath();
// this won't work if we aren't at top level
String cname = cpath == "" ? "i2psnark" : cpath.substring(1).replace("/", "_");
return (new File(_context.getBaseDir(), "webapps/" + cname + ".war")).lastModified();
}
public int getCacheTime()
{
return WAR_CACHE_CONTROL_SECS;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return -1;
}
/* ------------------------------------------------------------ */
public InputStream getInputStream() throws IOException
{
InputStream rv = getServletContext().getResourceAsStream(_path);
if (rv == null)
throw new IOException("Not found");
return rv;
}
@Override
public String toString() { return "Jar resource \"" + _path + '"'; }
}
/**
* @param resourcePath in the classpath, without ".properties" extension
*/
protected void loadMimeMap(String resourcePath) {
_mimeTypes.loadMimeMap(resourcePath);
}
/* ------------------------------------------------------------ */
/** Get the MIME type by filename extension.
* @param filename A file name
* @return MIME type matching the longest dot extension of the
* file name.
*/
protected String getMimeType(String filename) {
String rv = _mimeTypes.getMimeByExtension(filename);
if (rv != null)
return rv;
return getServletContext().getMimeType(filename);
}
protected void addMimeMapping(String extension, String type) {
_mimeTypes.addMimeMapping(extension, type);
}
/**
* Simple version of URIUtil.addPaths()
* @param path may be null
*/
protected static String addPaths(String base, String path) {
if (path == null)
return base;
return (new File(base, path)).toString();
}
/**
* Simple version of URIUtil.decodePath()
*/
protected static String decodePath(String path) throws MalformedURLException {
if (!path.contains("%"))
return path;
try {
URI uri = new URI(path);
return uri.getPath();
} catch (URISyntaxException use) {
// for ease of use, since a USE is not an IOE but a MUE is...
throw new MalformedURLException(use.getMessage());
}
}
/**
* Simple version of URIUtil.encodePath()
*/
protected static String encodePath(String path) throws MalformedURLException {
try {
URI uri = new URI(null, null, path, null);
return uri.toString();
} catch (URISyntaxException use) {
// for ease of use, since a USE is not an IOE but a MUE is...
throw new MalformedURLException(use.getMessage());
}
}
/**
* Write from in to out
*/
private void copy(InputStream in, OutputStream out) throws IOException {
ByteArray ba = _cache.acquire();
byte[] buf = ba.getData();
try {
int read = 0;
while ( (read = in.read(buf)) != -1) {
out.write(buf, 0, read);
}
} finally {
_cache.release(ba, false);
if (in != null)
try { in.close(); } catch (IOException ioe) {}
if (out != null)
try { out.close(); } catch (IOException ioe) {}
}
}
}

View File

@@ -24,6 +24,7 @@ import java.util.TreeSet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -44,42 +45,48 @@ import org.klomp.snark.Tracker;
import org.klomp.snark.TrackerClient;
import org.klomp.snark.dht.DHT;
import org.mortbay.jetty.servlet.DefaultServlet;
import org.mortbay.resource.Resource;
import org.mortbay.util.URIUtil;
/**
* We extend Default instead of HTTPServlet so we can handle
* i2psnark/ file requests with http:// instead of the flaky and
* often-blocked-by-the-browser file://
* Refactored to eliminate Jetty dependencies.
*/
public class I2PSnarkServlet extends DefaultServlet {
private I2PAppContext _context;
private Log _log;
public class I2PSnarkServlet extends BasicServlet {
/** generally "/i2psnark" */
private String _contextPath;
/** generally "i2psnark" */
private String _contextName;
private SnarkManager _manager;
private static long _nonce;
private Resource _resourceBase;
private String _themePath;
private String _imgPath;
private String _lastAnnounceURL;
private static final String DEFAULT_NAME = "i2psnark";
public static final String PROP_CONFIG_FILE = "i2psnark.configFile";
public I2PSnarkServlet() {
super();
}
@Override
public void init(ServletConfig cfg) throws ServletException {
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(I2PSnarkServlet.class);
super.init(cfg);
String cpath = getServletContext().getContextPath();
_contextPath = cpath == "" ? "/" : cpath;
_contextName = cpath == "" ? DEFAULT_NAME : cpath.substring(1).replace("/", "_");
_nonce = _context.random().nextLong();
_manager = new SnarkManager(_context);
// limited protection against overwriting other config files or directories
// in case you named your war "router.war"
String configName = _contextName;
if (!configName.equals(DEFAULT_NAME))
configName = DEFAULT_NAME + '_' + _contextName;
_manager = new SnarkManager(_context, _contextPath, configName);
String configFile = _context.getProperty(PROP_CONFIG_FILE);
if ( (configFile == null) || (configFile.trim().length() <= 0) )
configFile = "i2psnark.config";
configFile = configName + ".config";
_manager.loadConfig(configFile);
_manager.start();
try {
_resourceBase = Resource.newResource(_manager.getDataDir().getAbsolutePath());
} catch (IOException ioe) {}
super.init(cfg);
loadMimeMap("org/klomp/snark/web/mime");
setResourceBase(_manager.getDataDir());
setWarBase("/.icons/");
}
@Override
@@ -95,29 +102,36 @@ public class I2PSnarkServlet extends DefaultServlet {
* and we can't get any resources (like icons) out of the .war
*/
@Override
public Resource getResource(String pathInContext)
public File getResource(String pathInContext)
{
if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") ||
pathInContext.equals("/index.html") || pathInContext.startsWith("/.icons/"))
return super.getResource(pathInContext);
// files in the i2psnark/ directory
try {
return _resourceBase.addPath(pathInContext);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
return new File(_resourceBase, pathInContext);
}
/**
* Tell the browser to cache the icons
* Handle what we can here, calling super.doGet() for the rest.
* @since 0.8.3
*/
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.doGet(request, response);
doGetAndPost(request, response);
}
/**
* Handle what we can here, calling super.doPost() for the rest.
* @since Jetty 7
*/
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGetAndPost(request, response);
}
/**
* Handle what we can here, calling super.doGet() or super.doPost() for the rest.
*
* Some parts modified from:
* <pre>
// ========================================================================
@@ -137,14 +151,11 @@ public class I2PSnarkServlet extends DefaultServlet {
* </pre>
*
*/
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
private void doGetAndPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Service " + req.getMethod() + " \"" + req.getContextPath() + "\" \"" + req.getServletPath() + "\" \"" + req.getPathInfo() + '"');
// since we are not overriding handle*(), do this here
String method = req.getMethod();
if (!(method.equals("GET") || method.equals("HEAD") || method.equals("POST"))) {
resp.sendError(405);
return;
}
_themePath = "/themes/snark/" + _manager.getTheme() + '/';
_imgPath = _themePath + "images/";
// this is the part after /i2psnark
@@ -176,17 +187,18 @@ public class I2PSnarkServlet extends DefaultServlet {
// index.jsp doesn't work, it is grabbed by the war handler before here
if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || path.equals("/_post") || isConfigure)) {
if (path.endsWith("/")) {
// Listing of a torrent (torrent detail page)
// bypass the horrid Resource.getListHTML()
String pathInfo = req.getPathInfo();
String pathInContext = URIUtil.addPaths(path, pathInfo);
String pathInContext = addPaths(path, pathInfo);
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
Resource resource = getResource(pathInContext);
if (resource == null || (!resource.exists())) {
File resource = getResource(pathInContext);
if (resource == null) {
resp.sendError(404);
} else {
String base = URIUtil.addPaths(req.getRequestURI(), "/");
String base = addPaths(req.getRequestURI(), "/");
String listing = getListHTML(resource, base, true, method.equals("POST") ? req.getParameterMap() : null);
if (method.equals("POST")) {
// P-R-G
@@ -198,11 +210,19 @@ public class I2PSnarkServlet extends DefaultServlet {
}
}
} else {
super.service(req, resp);
// local completed files in torrent directories
if (method.equals("GET") || method.equals("HEAD"))
super.doGet(req, resp);
else if (method.equals("POST"))
super.doPost(req, resp);
else
resp.sendError(405);
}
return;
}
// Either the main page or /configure
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=UTF-8");
@@ -236,7 +256,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("<script src=\"/js/ajax.js\" type=\"text/javascript\"></script>\n" +
"<script type=\"text/javascript\">\n" +
"var failMessage = \"<div class=\\\"routerdown\\\"><b>" + _("Router is down") + "<\\/b><\\/div>\";\n" +
"function requestAjax1() { ajax(\"/i2psnark/.ajax/xhr1.html" + peerString + "\", \"mainsection\", " + (delay*1000) + "); }\n" +
"function requestAjax1() { ajax(\"" + _contextPath + "/.ajax/xhr1.html" + peerString + "\", \"mainsection\", " + (delay*1000) + "); }\n" +
"function initAjax() { setTimeout(requestAjax1, " + (delay*1000) +"); }\n" +
"</script>\n");
}
@@ -249,18 +269,24 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("<center>");
List<Tracker> sortedTrackers = null;
if (isConfigure) {
out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"");
out.write("<div class=\"snarknavbar\"><a href=\"" + _contextPath + "/\" title=\"");
out.write(_("Torrents"));
out.write("\" class=\"snarkRefresh\">");
out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;");
out.write(_("I2PSnark"));
if (_contextName.equals(DEFAULT_NAME))
out.write(_("I2PSnark"));
else
out.write(_contextName);
out.write("</a>");
} else {
out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/" + peerString + "\" title=\"");
out.write("<div class=\"snarknavbar\"><a href=\"" + _contextPath + '/' + peerString + "\" title=\"");
out.write(_("Refresh page"));
out.write("\" class=\"snarkRefresh\">");
out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;");
out.write(_("I2PSnark"));
if (_contextName.equals(DEFAULT_NAME))
out.write(_("I2PSnark"));
else
out.write(_contextName);
out.write("</a> <a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\" target=\"_blank\">");
out.write(_("Forum"));
out.write("</a>\n");
@@ -302,7 +328,7 @@ public class I2PSnarkServlet extends DefaultServlet {
List<String> msgs = _manager.getMessages();
if (!msgs.isEmpty()) {
out.write("<div class=\"snarkMessages\">");
out.write("<a href=\"/i2psnark/");
out.write("<a href=\"" + _contextPath + '/');
if (isConfigure)
out.write("configure");
if (peerString.length() > 0)
@@ -342,7 +368,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write(_("Status"));
out.write("\"></th>\n<th>");
if (_manager.util().connected() && !snarks.isEmpty()) {
out.write(" <a href=\"/i2psnark/");
out.write(" <a href=\"" + _contextPath + '/');
if (peerParam != null) {
out.write("\">");
out.write("<img border=\"0\" src=\"" + _imgPath + "hidepeers.png\" title=\"");
@@ -423,7 +449,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("&nbsp;");
} else if (_manager.util().connected()) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"" + _contextPath + "/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
else {
// http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
//out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
@@ -437,7 +463,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("</a>");
} else if ((!_manager.util().isConnecting()) && !snarks.isEmpty()) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"/" + _contextPath + "/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_StartAll\" value=\"foo\" title=\"");
out.write(_("Start all torrents and the I2P tunnel"));
@@ -450,7 +476,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("&nbsp;");
}
out.write("</th></tr></thead>\n");
String uri = "/i2psnark/";
String uri = _contextPath + '/';
boolean showDebug = "2".equals(peerParam);
for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i);
@@ -1245,7 +1271,7 @@ public class I2PSnarkServlet extends DefaultServlet {
} else if (isRunning) {
// Stop Button
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"" + _contextPath + "/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Stop_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Stop the torrent"));
@@ -1259,7 +1285,7 @@ public class I2PSnarkServlet extends DefaultServlet {
// Start Button
// This works in Opera but it's displayed a little differently, so use noThinsp here too so all 3 icons are consistent
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"/" + _contextPath + "/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Start_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Start the torrent"));
@@ -1273,7 +1299,7 @@ public class I2PSnarkServlet extends DefaultServlet {
// Remove Button
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"" + _contextPath + "/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Remove_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
@@ -1293,7 +1319,7 @@ public class I2PSnarkServlet extends DefaultServlet {
// Delete Button
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<a href=\"" + _contextPath + "/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Delete the .torrent file and the associated data file(s)"));
@@ -1620,7 +1646,7 @@ public class I2PSnarkServlet extends DefaultServlet {
boolean useDHT = _manager.util().shouldUseDHT();
//int seedPct = 0;
out.write("<form action=\"/i2psnark/configure\" method=\"POST\">\n" +
out.write("<form action=\"" + _contextPath + "/configure\" method=\"POST\">\n" +
"<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n" +
"<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n" +
"<input type=\"hidden\" name=\"action\" value=\"Save\" >\n" +
@@ -1632,7 +1658,8 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write(_("Data directory"));
out.write(": <td><code>" + dataDir + "</code> <i>(");
out.write(_("Edit i2psnark.config and restart to change"));
// translators: parameter is a file name
out.write(_("Edit {0} and restart to change", _manager.getConfigFilename()));
out.write(")</i><br>\n" +
"<tr><td>");
@@ -1802,7 +1829,7 @@ public class I2PSnarkServlet extends DefaultServlet {
/** @since 0.9 */
private void writeTrackerForm(PrintWriter out, HttpServletRequest req) throws IOException {
StringBuilder buf = new StringBuilder(1024);
buf.append("<form action=\"/i2psnark/configure\" method=\"POST\">\n" +
buf.append("<form action=\"" + _contextPath + "/configure\" method=\"POST\">\n" +
"<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n" +
"<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n" +
"<input type=\"hidden\" name=\"action\" value=\"Save2\" >\n" +
@@ -2031,7 +2058,7 @@ public class I2PSnarkServlet extends DefaultServlet {
* @return String of HTML or null if postParams != null
* @since 0.7.14
*/
private String getListHTML(Resource r, String base, boolean parent, Map postParams)
private String getListHTML(File r, String base, boolean parent, Map postParams)
throws IOException
{
String[] ls = null;
@@ -2040,9 +2067,10 @@ public class I2PSnarkServlet extends DefaultServlet {
Arrays.sort(ls, Collator.getInstance());
} // if r is not a directory, we are only showing torrent info section
String title = URIUtil.decodePath(base);
if (title.startsWith("/i2psnark/"))
title = title.substring("/i2psnark/".length());
String title = decodePath(base);
String cpath = _contextPath + '/';
if (title.startsWith(cpath))
title = title.substring(cpath.length());
// Get the snark associated with this directory
String torrentName;
@@ -2067,8 +2095,13 @@ public class I2PSnarkServlet extends DefaultServlet {
title = _("Torrent") + ": " + title;
buf.append(title);
buf.append("</TITLE>").append(HEADER_A).append(_themePath).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">" +
"</HEAD><BODY>\n<center><div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"Torrents\"");
buf.append(" class=\"snarkRefresh\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;I2PSnark</a></div></center>\n");
"</HEAD><BODY>\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"");
buf.append(" class=\"snarkRefresh\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\">&nbsp;&nbsp;");
if (_contextName.equals(DEFAULT_NAME))
buf.append(_("I2PSnark"));
else
buf.append(_contextName);
buf.append("</a></div></center>\n");
if (parent) // always true
buf.append("<div class=\"page\"><div class=\"mainsection\">");
@@ -2089,7 +2122,7 @@ public class I2PSnarkServlet extends DefaultServlet {
buf.append("<tr><td>")
.append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" >&nbsp;<b>")
.append(_("Torrent file"))
.append(":</b> <a href=\"/i2psnark/").append(baseName).append("\">")
.append(":</b> <a href=\"").append(_contextPath).append('/').append(baseName).append("\">")
.append(fullPath)
.append("</a></td></tr>\n");
@@ -2228,7 +2261,7 @@ public class I2PSnarkServlet extends DefaultServlet {
.append("\"></th>\n");
buf.append("</tr>\n</thead>\n");
buf.append("<tr><td colspan=\"" + (showPriority ? '5' : '4') + "\" class=\"ParentDir\"><A HREF=\"");
buf.append(URIUtil.addPaths(base,"../"));
buf.append(addPaths(base,"../"));
buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ")
.append(_("Up to higher level directory"))
.append("</A></td></tr>\n");
@@ -2239,12 +2272,12 @@ public class I2PSnarkServlet extends DefaultServlet {
boolean showSaveButton = false;
for (int i=0 ; i< ls.length ; i++)
{
String encoded=URIUtil.encodePath(ls[i]);
String encoded = 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 = r.addPath(ls[i]);
File item = new File(r, ls[i]);
String rowClass = (i % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
buf.append("<TR class=\"").append(rowClass).append("\">");
@@ -2264,7 +2297,7 @@ public class I2PSnarkServlet extends DefaultServlet {
} else {
Storage storage = snark.getStorage();
try {
File f = item.getFile();
File f = item;
if (f != null) {
long remaining = storage.remaining(f.getCanonicalPath());
if (remaining < 0) {
@@ -2294,9 +2327,9 @@ public class I2PSnarkServlet extends DefaultServlet {
}
}
String path=URIUtil.addPaths(base,encoded);
String path=addPaths(base,encoded);
if (item.isDirectory() && !path.endsWith("/"))
path=URIUtil.addPaths(path,"/");
path=addPaths(path,"/");
String icon = toIcon(item);
buf.append("<TD class=\"snarkFileIcon ")
@@ -2331,7 +2364,7 @@ public class I2PSnarkServlet extends DefaultServlet {
buf.append("</TD>");
if (showPriority) {
buf.append("<td class=\"priority\">");
File f = item.getFile();
File f = item;
if ((!complete) && (!item.isDirectory()) && f != null) {
int pri = snark.getStorage().getPriority(f.getCanonicalPath());
buf.append("<input type=\"radio\" value=\"5\" name=\"pri.").append(f.getCanonicalPath()).append("\" ");
@@ -2368,7 +2401,7 @@ public class I2PSnarkServlet extends DefaultServlet {
}
/** @since 0.7.14 */
private String toIcon(Resource item) {
private String toIcon(File item) {
if (item.isDirectory())
return "folder";
return toIcon(item.toString());
@@ -2381,40 +2414,32 @@ public class I2PSnarkServlet extends DefaultServlet {
*/
private String toIcon(String path) {
String icon;
// Should really just add to the mime.properties file in org.mortbay.jetty.jar
// instead of this mishmash. We can't get to HttpContext.setMimeMapping()
// from here? We could do it from a web.xml perhaps.
// Or could we put our own org/mortbay/http/mime.properties file in the war?
// Note that for this to work well, our custom mime.properties file must be loaded.
String plc = path.toLowerCase(Locale.US);
String mime = getServletContext().getMimeType(path);
String mime = getMimeType(path);
if (mime == null)
mime = "";
if (mime.equals("text/html"))
icon = "html";
else if (mime.equals("text/plain") || plc.endsWith(".nfo") ||
else if (mime.equals("text/plain") ||
mime.equals("application/rtf"))
icon = "page";
else if (mime.equals("application/java-archive") || plc.endsWith(".war") ||
else if (mime.equals("application/java-archive") ||
plc.endsWith(".deb"))
icon = "package";
else if (plc.endsWith(".xpi2p"))
icon = "plugin";
else if (mime.equals("application/pdf"))
icon = "page_white_acrobat";
else if (mime.startsWith("image/") || plc.endsWith(".ico"))
else if (mime.startsWith("image/"))
icon = "photo";
else if (mime.startsWith("audio/") || mime.equals("application/ogg") ||
plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") ||
plc.endsWith(".ape") || plc.endsWith(".oga"))
else if (mime.startsWith("audio/") || mime.equals("application/ogg"))
icon = "music";
else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") ||
plc.endsWith(".mp4") || plc.endsWith(".wmv") || plc.endsWith(".flv") ||
plc.endsWith(".ogm") || plc.endsWith(".ogv"))
else if (mime.startsWith("video/"))
icon = "film";
else if (mime.equals("application/zip") || mime.equals("application/x-gtar") ||
mime.equals("application/compress") || mime.equals("application/gzip") ||
mime.equals("application/x-tar") ||
plc.endsWith(".rar") || plc.endsWith(".bz2") || plc.endsWith(".7z"))
mime.equals("application/x-tar"))
icon = "compress";
else if (plc.endsWith(".exe"))
icon = "application";
@@ -2426,13 +2451,13 @@ public class I2PSnarkServlet extends DefaultServlet {
}
/** @since 0.7.14 */
private static String toImg(String icon) {
return "<img alt=\"\" height=\"16\" width=\"16\" src=\"/i2psnark/.icons/" + icon + ".png\">";
private String toImg(String icon) {
return "<img alt=\"\" height=\"16\" width=\"16\" src=\"" + _contextPath + "/.icons/" + icon + ".png\">";
}
/** @since 0.8.2 */
private static String toImg(String icon, String altText) {
return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"/i2psnark/.icons/" + icon + ".png\">";
private String toImg(String icon, String altText) {
return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"" + _contextPath + "/.icons/" + icon + ".png\">";
}
/** @since 0.8.1 */

View File

@@ -0,0 +1,131 @@
// ========================================================================
// Copyright 2000-2005 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.klomp.snark.web;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
/* ------------------------------------------------------------ */
/**
* Based on MimeTypes from Jetty 6.1.26, heavily simplified
* and modified to remove all dependencies on Jetty libs.
*
* Supports mime types only, not encodings.
* Does not support a default "*" mapping.
*
* This is only for local mappings.
* Caller should use getServletContext().getMimeType() if this returns null.
*
*
* ------------------------------------------------------------
*
* @author Greg Wilkins
*
* @since Jetty 7
*/
class MimeTypes
{
private final Map<String, String> _mimeMap;
public MimeTypes() {
_mimeMap = new ConcurrentHashMap();
}
/* ------------------------------------------------------------ */
/**
* @param resourcePath A Map of file extension to mime-type.
*/
public void loadMimeMap(String resourcePath) {
loadMimeMap(_mimeMap, resourcePath);
}
/**
* Tries both webapp and system class loader, since Jetty blocks
* its classes from the webapp class loader.
*/
private static void loadMimeMap(Map<String, String> map, String resourcePath) {
try
{
ResourceBundle mime;
try {
mime = ResourceBundle.getBundle(resourcePath);
} catch(MissingResourceException e) {
// Jetty 7 webapp classloader blocks jetty classes
// http://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading
//System.out.println("No mime types loaded from " + resourcePath + ", trying system classloader");
mime = ResourceBundle.getBundle(resourcePath, Locale.getDefault(), ClassLoader.getSystemClassLoader());
}
Enumeration<String> i = mime.getKeys();
while(i.hasMoreElements())
{
String ext = i.nextElement();
String m = mime.getString(ext);
map.put(ext.toLowerCase(Locale.US), m);
}
//System.out.println("Loaded " + map.size() + " mime types from " + resourcePath);
} catch(MissingResourceException e) {
//System.out.println("No mime types loaded from " + resourcePath);
}
}
/* ------------------------------------------------------------ */
/** Get the MIME type by filename extension.
*
* Returns ONLY local mappings.
* Caller should use getServletContext().getMimeType() if this returns null.
*
* @param filename A file name
* @return MIME type matching the longest dot extension of the
* file name.
*/
public String getMimeByExtension(String filename)
{
String type=null;
if (filename!=null)
{
int i=-1;
while(type==null)
{
i=filename.indexOf(".",i+1);
if (i<0 || i>=filename.length())
break;
String ext=filename.substring(i+1).toLowerCase(Locale.US);
type = _mimeMap.get(ext);
}
}
return type;
}
/* ------------------------------------------------------------ */
/** Set a mime mapping
* @param extension
* @param type
*/
public void addMimeMapping(String extension, String type)
{
_mimeMap.put(extension.toLowerCase(Locale.US), type);
}
}

View File

@@ -5,7 +5,7 @@ import java.io.File;
import net.i2p.I2PAppContext;
import net.i2p.util.FileUtil;
import org.mortbay.jetty.Server;
import org.eclipse.jetty.server.Server;
public class RunStandalone {
static {

View File

@@ -0,0 +1,19 @@
package org.klomp.snark.web;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
/**
* Treat a writer as an output stream. Quick 'n dirty, none
* of that "intarnasheeonaleyzayshun" stuff. So we can treat
* the jsp's PrintWriter as an OutputStream
*
* @since Jetty 7 copied from routerconsole
*/
class WriterOutputStream extends OutputStream {
private final Writer _writer;
public WriterOutputStream(Writer writer) { _writer = writer; }
public void write(int b) throws IOException { _writer.write(b); }
}

View File

@@ -0,0 +1,17 @@
7z = application/x-7z-compressed
ape = audio/ape
bz2 = application/x-bzip2
flac = audio/ogg
flv = video/x-flv
m4a = audio/mp4a-latm
m4v = video/x-m4v
mkv = video/x-matroska
mp4 = video/mp4
nfo = text/plain
ogm = video/ogg
ogv = video/ogg
oga = audio/ogg
rar = application/x-rar-compressed
war = application/java-archive
wma = audio/x-ms-wma
wmv = video/x-ms-wmv

View File

@@ -0,0 +1,3 @@
jetty-distribution-xxx is only what we need out of jetty-distribution-xxx.zip.
NOTICE and LICENSE files moved to ../../../licenses

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="jetty">
<property name="jetty.ver" value="6.1.26" />
<property name="jetty.base" value="jetty-${jetty.ver}" />
<property name="jetty.sha1" value="9485913f1a1945a849a90f1a34853d22350bc524" />
<property name="jetty.ver" value="7.6.8.v20121106" />
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
<property name="jetty.sha1" value="6fcdc3f532c5ab72843e12cbac3d7cb797cdb5b9" />
<property name="jetty.filename" value="${jetty.base}.zip" />
<property name="jetty.url" value="http://dist.codehaus.org/jetty/${jetty.base}/${jetty.filename}" />
<property name="jetty.url" value="http://download.eclipse.org/jetty/${jetty.ver}/dist/${jetty.filename}" />
<property name="verified.filename" value="verified.txt" />
<property name="javac.compilerargs" value="" />
<property name="tomcat.lib" value="apache-tomcat-deployer/lib" />
@@ -89,20 +89,40 @@
Reasons for inclusion:
start.jar: Needed for clients.config startup of eepsites
jetty-util-xxx.jar: LifeCycle (base class for stuff), URIUtil (used in i2psnark)
jetty-sslengine-xxx.jar: SSL NIO Connector for console
jetty-java5-threadpool-xxx.jar: Concurrent thread pool for eepsite
jetty-deploy, -http, -io, -security, -servlet, -webapp: All split out from main server jar in Jetty 7
jetty-continuation-xxx.jar: Needed? Useful?
jetty-servlets-xxx.jar: Needed for CGI for eepsite
jetty-sslengine-xxx.jar: Old Jetty 6, now a dummy
jetty-java5-threadpool-xxx.jar: Old Jetty 6, now a dummy
glassfish 2.1: Not used, too old, see Tomcat below.
jetty-rewrite-handler: Not used by I2P, but only 20KB and could be useful for eepsites
jetty-management: Not used by I2P, but only 34KB and could be useful for eepsites, and we bundled it with Jetty 5
All of these are available in the Ubuntu packages libjetty-java and libjetty-extra-java
-->
<copy preservelastmodified="true" file="${jetty.base}/start.jar" tofile="jettylib/jetty-start.jar" />
<copy file="${jetty.base}/lib/${jetty.base}.jar" tofile="jettylib/org.mortbay.jetty.jar" />
<copy file="${jetty.base}/lib/jetty-server-${jetty.ver}.jar" tofile="jettylib/org.mortbay.jetty.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-continuation-${jetty.ver}.jar" tofile="jettylib/jetty-continuation.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-deploy-${jetty.ver}.jar" tofile="jettylib/jetty-deploy.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-http-${jetty.ver}.jar" tofile="jettylib/jetty-http.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-io-${jetty.ver}.jar" tofile="jettylib/jetty-io.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-jmx-${jetty.ver}.jar" tofile="jettylib/org.mortbay.jmx.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-rewrite-${jetty.ver}.jar" tofile="jettylib/jetty-rewrite-handler.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-security-${jetty.ver}.jar" tofile="jettylib/jetty-security.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-servlet-${jetty.ver}.jar" tofile="jettylib/jetty-servlet.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-servlets-${jetty.ver}.jar" tofile="jettylib/jetty-servlets.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/ext/jetty-java5-threadpool-${jetty.ver}.jar" tofile="jettylib/jetty-java5-threadpool.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/ext/jetty-rewrite-handler-${jetty.ver}.jar" tofile="jettylib/jetty-rewrite-handler.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/management/jetty-management-${jetty.ver}.jar" tofile="jettylib/org.mortbay.jmx.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-webapp-${jetty.ver}.jar" tofile="jettylib/jetty-webapp.jar" />
<copy preservelastmodified="true" file="${jetty.base}/lib/jetty-xml-${jetty.ver}.jar" tofile="jettylib/jetty-xml.jar" />
<jar destfile="jettylib/jetty-java5-threadpool.jar" >
<manifest>
<attribute name="Note" value="Intentionally empty" />
</manifest>
</jar>
<jar destfile="jettylib/jetty-sslengine.jar" >
<manifest>
<attribute name="Note" value="Intentionally empty" />
</manifest>
</jar>
<delete file="jetty.tar" />
<!--
<delete dir="${jetty.base}" />
@@ -155,15 +175,16 @@
<target name="build" depends="jar" />
<target name="builddep" />
<target name="compile" depends="builddep, ensureJettylib" >
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
srcdir="./java/src"
debug="true" source="1.5" target="1.5"
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
includeAntRuntime="false"
classpath="../../core/java/build/i2p.jar:./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-util.jar" >
classpath="../../core/java/build/i2p.jar:./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-http.jar:./jettylib/jetty-io.jar:./jettylib/jetty-util.jar:./jettylib/jetty-xml.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>

View File

@@ -17,13 +17,13 @@ package net.i2p.jetty;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
import org.mortbay.jetty.Server;
import org.mortbay.log.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Logger;
/**
* Modified from Jetty 6.1.26 StdErrLog.java and Slf4jLog.java
*
* Usage: org.mortbay.log.Log.setLog(new I2PLogger(ctx));
* Usage: org.eclipse.log.Log.setLog(new I2PLogger(ctx));
*
* @since Jetty 6
*/
@@ -182,5 +182,80 @@ public class I2PLogger implements Logger
return "I2PLogger";
}
/**
* @since Jetty 7
*/
public void ignore(Throwable ignored)
{
warn("IGNORED", ignored);
}
/**
* @since Jetty 7
*/
public void debug(Throwable thrown)
{
debug("", thrown);
}
/**
* @since Jetty 7
*/
public void debug(String msg, Object... args)
{
Object a1 = args.length > 0 ? args[0] : null;
Object a2 = args.length > 1 ? args[1] : null;
debug(msg, a1, a2);
}
/**
* @since Jetty 7
*/
public void info(Throwable thrown)
{
info("", thrown);
}
/**
* @since Jetty 7
*/
public void info(String msg, Object... args)
{
Object a1 = args.length > 0 ? args[0] : null;
Object a2 = args.length > 1 ? args[1] : null;
info(msg, a1, a2);
}
/**
* @since Jetty 7
*/
public void info(String msg, Throwable th)
{
_log.info(msg,th);
}
/**
* @since Jetty 7
*/
public void warn(Throwable thrown)
{
warn("", thrown);
}
/**
* @since Jetty 7
*/
public void warn(String msg, Object... args)
{
Object a1 = args.length > 0 ? args[0] : null;
Object a2 = args.length > 1 ? args[1] : null;
warn(msg, a1, a2);
}
/**
* @since Jetty 7
*/
public String getName() {
return "net.i2p.jetty.I2PLogger";
}
}

View File

@@ -24,18 +24,18 @@ import java.util.TimeZone;
import javax.servlet.http.Cookie;
import org.mortbay.component.AbstractLifeCycle;
import org.mortbay.jetty.HttpHeaders;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.RequestLog;
import org.mortbay.jetty.Response;
import org.mortbay.jetty.servlet.PathMap;
import org.mortbay.log.Log;
import org.mortbay.util.DateCache;
import org.mortbay.util.RolloverFileOutputStream;
import org.mortbay.util.StringUtil;
import org.mortbay.util.TypeUtil;
import org.mortbay.util.Utf8StringBuffer;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.DateCache;
import org.eclipse.jetty.util.RolloverFileOutputStream;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
/**
* This {@link RequestLog} implementation outputs logs in the pseudo-standard NCSA common log format.
@@ -56,8 +56,6 @@ import org.mortbay.util.Utf8StringBuffer;
*
* So that we will work with system Jetty 6 packages, we just copy the whole thing
* and modify log() as required.
* We leave the package as org.mortbay.http for compatibility with old
* jetty.xml files.
*
* @author Greg Wilkins
* @author Nigel Canonizado
@@ -259,13 +257,13 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
if (_fileOut == null)
return;
Utf8StringBuffer u8buf;
StringBuffer buf;
Utf8StringBuilder u8buf;
StringBuilder buf;
synchronized(_writer)
{
int size=_buffers.size();
u8buf = size==0?new Utf8StringBuffer(160):(Utf8StringBuffer)_buffers.remove(size-1);
buf = u8buf.getStringBuffer();
u8buf = size==0?new Utf8StringBuilder(160):(Utf8StringBuilder)_buffers.remove(size-1);
buf = u8buf.getStringBuilder();
}
synchronized(buf) // for efficiency until we can use StringBuilder
@@ -398,7 +396,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog
if (_logLatency)
{
_writer.write(' ');
_writer.write(TypeUtil.toString(System.currentTimeMillis() - request.getTimeStamp()));
_writer.write(Long.toString(System.currentTimeMillis() - request.getTimeStamp()));
}
_writer.write(StringUtil.__LINE_SEPARATOR);

View File

@@ -19,15 +19,16 @@ package net.i2p.jetty;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.app.*;
import static net.i2p.app.ClientAppState.*;
import org.mortbay.component.LifeCycle;
import org.mortbay.resource.Resource;
import org.mortbay.xml.XmlConfiguration;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
/**
* Start Jetty where the args are one or more XML files.
@@ -73,8 +74,11 @@ public class JettyStart implements ClientApp {
XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURL());
if (last!=null)
configuration.getIdMap().putAll(last.getIdMap());
if (properties.size()>0)
configuration.setProperties(properties);
if (properties.size()>0) {
// to avoid compiler errror
Map foo = configuration.getProperties();
foo.putAll(properties);
}
Object o = configuration.configure();
if (o instanceof LifeCycle)
_jettys.add((LifeCycle)o);

View File

@@ -1,3 +0,0 @@
This is only what we need out of the 25 MB Jetty-6.1.26.zip.
NOTICE and LICENSE files moved to ../../../licenses

Binary file not shown.

View File

@@ -63,9 +63,13 @@
<pathelement location="../../../core/java/build/i2p.jar" />
<pathelement location="../../../router/java/build/router.jar" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/jetty-http.jar" />
<pathelement location="../../jetty/jettylib/jetty-io.jar" />
<pathelement location="../../jetty/jettylib/jetty-security.jar" />
<pathelement location="../../jetty/jettylib/jetty-servlet.jar" />
<pathelement location="../../jetty/jettylib/jetty-servlets.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="../../jetty/jettylib/jetty-sslengine.jar" />
<pathelement location="../../jetty/jettylib/jetty-java5-threadpool.jar" />
<pathelement location="../../jetty/jettylib/jetty-webapp.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="../../jetty/jettylib/jetty-i2p.jar" />

View File

@@ -17,7 +17,7 @@ import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.router.update.ConsoleUpdateManager;
import static net.i2p.update.UpdateType.*;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
/**
* Saves changes to clients.config or webapps.config

View File

@@ -12,7 +12,7 @@ import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.util.RouterPasswordManager;
//import org.mortbay.jetty.security.UnixCrypt;
//import org.eclipse.jetty.util.security.UnixCrypt;
/**
* Manage both plaintext and salted/hashed password storage in

View File

@@ -1,5 +1,6 @@
package net.i2p.router.web;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
@@ -10,7 +11,11 @@ import javax.servlet.http.HttpServletResponse;
import net.i2p.I2PAppContext;
import org.mortbay.jetty.webapp.WebAppContext;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Convert foo.jsp to foo_xx.jsp for language xx.
@@ -21,14 +26,22 @@ import org.mortbay.jetty.webapp.WebAppContext;
*
* @author zzz
*/
public class LocaleWebAppHandler extends WebAppContext
public class LocaleWebAppHandler extends HandlerWrapper
{
private final I2PAppContext _context;
private final WebAppContext _wac;
public LocaleWebAppHandler(I2PAppContext ctx, String path, String warPath) {
super(warPath, path);
public LocaleWebAppHandler(I2PAppContext ctx, String path, String warPath,
File tmpdir, ServletHandler servletHandler) {
super();
_context = ctx;
_wac = new WebAppContext(warPath, path);
setInitParams(WebAppStarter.INIT_PARAMS);
_wac.setTempDirectory(tmpdir);
_wac.setExtractWAR(false);
_wac.setSessionHandler(new SessionHandler());
_wac.setServletHandler(servletHandler);
setHandler(_wac);
}
/**
@@ -37,19 +50,12 @@ public class LocaleWebAppHandler extends WebAppContext
* or as specified in the routerconsole.lang property.
* Unless language == "en".
*/
@Override
public void handle(String pathInContext,
Request baseRequest,
HttpServletRequest httpRequest,
HttpServletResponse httpResponse,
int dispatch)
HttpServletResponse httpResponse)
throws IOException, ServletException
{
// Handle OPTIONS (nothing to override)
if ("OPTIONS".equals(httpRequest.getMethod()))
{
handleOptions(httpRequest, httpResponse);
return;
}
// transparent rewriting
if (pathInContext.equals("/") || pathInContext.equals("/index.html")) {
@@ -77,7 +83,7 @@ public class LocaleWebAppHandler extends WebAppContext
if (lang != null && lang.length() > 0 && !lang.equals("en")) {
String testPath = pathInContext.substring(0, len - 4) + '_' + lang + ".jsp";
// Do we have a servlet for the new path that isn't the catchall *.jsp?
Map.Entry servlet = getServletHandler().getHolderEntry(testPath);
Map.Entry servlet = _wac.getServletHandler().getHolderEntry(testPath);
if (servlet != null) {
String servletPath = (String) servlet.getKey();
if (servletPath != null && !servletPath.startsWith("*")) {
@@ -90,7 +96,7 @@ public class LocaleWebAppHandler extends WebAppContext
}
}
//System.err.println("New path: " + newPath);
super.handle(newPath, httpRequest, httpResponse, dispatch);
super.handle(newPath, baseRequest, httpRequest, httpResponse);
//System.err.println("Was handled? " + httpRequest.isHandled());
}
@@ -112,10 +118,28 @@ public class LocaleWebAppHandler extends WebAppContext
* Not an override
* @since 0.8
*/
/**** not in Jetty 7
public void handleOptions(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
response.sendError(405);
}
****/
/**
* Mysteriously removed from Jetty 7
*/
private void setInitParams(Map params) {
setInitParams(_wac, params);
}
/**
* @since Jetty 7
*/
public static void setInitParams(WebAppContext context, Map<?,?> params) {
for (Map.Entry e : params.entrySet()) {
context.setInitParameter((String)e.getKey(), (String)e.getValue());
}
}
}

View File

@@ -7,7 +7,7 @@ import net.i2p.I2PAppContext;
import net.i2p.util.FileUtil;
import net.i2p.util.VersionComparator;
import org.mortbay.jetty.Server;
import org.eclipse.jetty.server.Server;
import org.tanukisoftware.wrapper.WrapperManager;
public class LogsHelper extends HelperBase {

View File

@@ -34,7 +34,7 @@ import net.i2p.util.Log;
import net.i2p.util.Translate;
import net.i2p.util.VersionComparator;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
/**

View File

@@ -42,30 +42,33 @@ import net.i2p.util.ShellCommand;
import net.i2p.util.SystemVersion;
import net.i2p.util.VersionComparator;
import org.mortbay.jetty.AbstractConnector;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.NCSARequestLog;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.handler.RequestLogHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.Credential.MD5;
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.SslSocketConnector;
import org.mortbay.jetty.security.SslSelectChannelConnector;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.jetty.servlet.SessionHandler;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.thread.QueuedThreadPool;
import org.mortbay.thread.concurrent.ThreadPool;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Credential;
import org.eclipse.jetty.util.security.Credential.MD5;
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
/**
* Start the router console.
@@ -293,7 +296,7 @@ public class RouterConsoleRunner implements RouterApp {
// System.err.println("INFO: I2P Jetty logging class not found, logging to wrapper log");
//}
// This way it doesn't try to load Slf4jLog first
System.setProperty("org.mortbay.log.class", "net.i2p.jetty.I2PLogger");
System.setProperty("org.eclipse.jetty.util.log.class", "net.i2p.jetty.I2PLogger");
// so Jetty can find WebAppConfiguration
System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
@@ -302,7 +305,8 @@ public class RouterConsoleRunner implements RouterApp {
try {
ThreadPool ctp = new CustomThreadPoolExecutor();
ctp.prestartAllCoreThreads();
// Gone in Jetty 7
//ctp.prestartAllCoreThreads();
_server.setThreadPool(ctp);
} catch (Throwable t) {
// class not found...
@@ -315,7 +319,9 @@ public class RouterConsoleRunner implements RouterApp {
HandlerCollection hColl = new HandlerCollection();
ContextHandlerCollection chColl = new ContextHandlerCollection();
_server.addHandler(hColl);
// gone in Jetty 7
//_server.addHandler(hColl);
_server.setHandler(hColl);
hColl.addHandler(chColl);
hColl.addHandler(new DefaultHandler());
@@ -351,7 +357,7 @@ public class RouterConsoleRunner implements RouterApp {
if (!_webAppsDir.endsWith("/"))
_webAppsDir += '/';
WebAppContext rootWebApp = null;
HandlerWrapper rootWebApp = null;
ServletHandler rootServletHandler = null;
List<Connector> connectors = new ArrayList(4);
try {
@@ -507,17 +513,14 @@ public class RouterConsoleRunner implements RouterApp {
return;
}
rootWebApp = new LocaleWebAppHandler(_context,
"/", _webAppsDir + ROUTERCONSOLE + ".war");
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
(_listenPort != null ? _listenPort : _sslListenPort));
tmpdir.mkdir();
rootWebApp.setTempDirectory(tmpdir);
rootWebApp.setExtractWAR(false);
rootWebApp.setSessionHandler(new SessionHandler());
rootServletHandler = new ServletHandler();
rootWebApp.setServletHandler(rootServletHandler);
initialize(_context, rootWebApp);
rootWebApp = new LocaleWebAppHandler(_context,
"/", _webAppsDir + ROUTERCONSOLE + ".war",
tmpdir, rootServletHandler);
initialize(_context, (WebAppContext)(rootWebApp.getHandler()));
chColl.addHandler(rootWebApp);
} catch (Exception ioe) {
@@ -727,7 +730,7 @@ public class RouterConsoleRunner implements RouterApp {
* Add all users and passwords.
*/
static void initialize(RouterContext ctx, WebAppContext context) {
SecurityHandler sec = new SecurityHandler();
ConstraintSecurityHandler sec = new ConstraintSecurityHandler();
List<ConstraintMapping> constraints = new ArrayList(4);
ConsolePasswordManager mgr = new ConsolePasswordManager(ctx);
boolean enable = ctx.getBooleanProperty(PROP_PW_ENABLE);
@@ -737,14 +740,13 @@ public class RouterConsoleRunner implements RouterApp {
enable = false;
ctx.router().saveConfig(PROP_CONSOLE_PW, "false");
} else {
HashUserRealm realm = new HashUserRealm(JETTY_REALM);
sec.setUserRealm(realm);
HashLoginService realm = new HashLoginService(JETTY_REALM);
sec.setLoginService(realm);
sec.setAuthenticator(authenticator);
for (Map.Entry<String, String> e : userpw.entrySet()) {
String user = e.getKey();
String pw = e.getValue();
realm.put(user, MD5.__TYPE + pw);
realm.addUserToRole(user, JETTY_ROLE);
realm.putUser(user, Credential.getCredential(MD5.__TYPE + pw), new String[] {JETTY_ROLE});
Constraint constraint = new Constraint(user, JETTY_ROLE);
constraint.setAuthenticate(true);
ConstraintMapping cm = new ConstraintMapping();
@@ -843,11 +845,13 @@ public class RouterConsoleRunner implements RouterApp {
* Just to set the name and set Daemon
* @since Jetty 6
*/
private static class CustomThreadPoolExecutor extends ThreadPool {
private static class CustomThreadPoolExecutor extends ExecutorThreadPool {
public CustomThreadPoolExecutor() {
super(MIN_THREADS, MAX_THREADS, MAX_IDLE_TIME, TimeUnit.MILLISECONDS,
new SynchronousQueue(), new CustomThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
new SynchronousQueue() /** , following args not available in Jetty 7
new CustomThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy() **/
);
}
}

View File

@@ -10,9 +10,9 @@ import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import org.mortbay.jetty.webapp.Configuration;
import org.mortbay.jetty.webapp.WebAppClassLoader;
import org.mortbay.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@@ -38,23 +38,15 @@ import org.mortbay.jetty.webapp.WebAppContext;
* @author zzz
*/
public class WebAppConfiguration implements Configuration {
private WebAppContext _wac;
private static final String CLASSPATH = ".classpath";
public void setWebAppContext(WebAppContext context) {
_wac = context;
}
public WebAppContext getWebAppContext() {
return _wac;
}
/**
* This was the interface in Jetty 5, now it's configureClassLoader()
* This was the interface in Jetty 5, in Jetty 6 was configureClassLoader(),
* now it's configure()
*/
private void configureClassPath() throws Exception {
String ctxPath = _wac.getContextPath();
private void configureClassPath(WebAppContext wac) throws Exception {
String ctxPath = wac.getContextPath();
//System.err.println("Configure Class Path " + ctxPath);
if (ctxPath.equals("/"))
return;
@@ -110,7 +102,7 @@ public class WebAppConfiguration implements Configuration {
}
if (buf.length() <= 0)
return;
ClassLoader cl = _wac.getClassLoader();
ClassLoader cl = wac.getClassLoader();
if (cl != null && cl instanceof WebAppClassLoader) {
WebAppClassLoader wacl = (WebAppClassLoader) cl;
wacl.addClassPath(buf.toString());
@@ -118,7 +110,7 @@ public class WebAppConfiguration implements Configuration {
// This was not working because the WebAppClassLoader already exists
// and it calls getExtraClasspath in its constructor
// Not sure why WACL already exists...
_wac.setExtraClasspath(buf.toString());
wac.setExtraClasspath(buf.toString());
}
}
@@ -133,14 +125,25 @@ public class WebAppConfiguration implements Configuration {
return rv;
}
public void configureDefaults() {}
public void configureWebApp() {}
/** @since Jetty 7 */
public void deconfigure(WebAppContext context) {}
/** @since Jetty 6 */
public void deconfigureWebApp() {}
/** @since Jetty 6 */
public void configureClassLoader() throws Exception {
configureClassPath();
/** @since Jetty 7 */
public void configure(WebAppContext context) throws Exception {
configureClassPath(context);
}
/** @since Jetty 7 */
public void cloneConfigure(WebAppContext template, WebAppContext context) {
// no state, nothing to be done
}
/** @since Jetty 7 */
public void destroy(WebAppContext context) {}
/** @since Jetty 7 */
public void preConfigure(WebAppContext context) {}
/** @since Jetty 7 */
public void postConfigure(WebAppContext context) {}
}

View File

@@ -10,11 +10,11 @@ import net.i2p.router.RouterContext;
import net.i2p.util.FileUtil;
import net.i2p.util.SecureDirectory;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@@ -56,7 +56,7 @@ public class WebAppStarter {
File tmpdir = new SecureDirectory(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
WebAppContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
//_log.debug("Loading war from: " + warPath);
wac.setInitParams(INIT_PARAMS);
LocaleWebAppHandler.setInitParams(wac, INIT_PARAMS);
wac.start();
}
@@ -155,6 +155,8 @@ public class WebAppStarter {
return null;
String path = '/'+ appName;
for (int i = 0; i < handlers.length; i++) {
if (!(handlers[i] instanceof ContextHandler))
continue;
ContextHandler ch = (ContextHandler) handlers[i];
if (path.equals(ch.getContextPath()))
return ch;

View File

@@ -4,9 +4,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// Let's make this easy...
final Integer ERROR_CODE = (Integer) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_STATUS_CODE);
final String ERROR_URI = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_REQUEST_URI);
final String ERROR_MESSAGE = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_MESSAGE);
final Integer ERROR_CODE = (Integer) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_STATUS_CODE);
final String ERROR_URI = (String) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_REQUEST_URI);
final String ERROR_MESSAGE = (String) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_MESSAGE);
if (ERROR_CODE != null && ERROR_MESSAGE != null) {
// this is deprecated but we don't want sendError()
response.setStatus(ERROR_CODE.intValue(), ERROR_MESSAGE);

View File

@@ -3,11 +3,11 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%
// Let's make this easy...
final Integer ERROR_CODE = (Integer) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_STATUS_CODE);
final String ERROR_URI = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_REQUEST_URI);
final String ERROR_MESSAGE = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_MESSAGE);
final Class ERROR_CLASS = (Class)request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_EXCEPTION_TYPE);
final Throwable ERROR_THROWABLE = (Throwable)request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_EXCEPTION);
final Integer ERROR_CODE = (Integer) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_STATUS_CODE);
final String ERROR_URI = (String) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_REQUEST_URI);
final String ERROR_MESSAGE = (String) request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_MESSAGE);
final Class ERROR_CLASS = (Class)request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_EXCEPTION_TYPE);
final Throwable ERROR_THROWABLE = (Throwable)request.getAttribute(org.eclipse.jetty.server.Dispatcher.ERROR_EXCEPTION);
if (ERROR_CODE != null && ERROR_MESSAGE != null) {
// this is deprecated but we don't want sendError()
response.setStatus(ERROR_CODE.intValue(), ERROR_MESSAGE);

View File

@@ -25,6 +25,7 @@
<pathelement location="../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../jetty/jettylib/jetty-util.jar" />
<pathelement location="../jetty/jettylib/jetty-http.jar" />
<pathelement location="../../core/java/build/i2p.jar" />
</classpath>
</javac>

View File

@@ -29,10 +29,10 @@ import javax.servlet.http.HttpServletRequest;
//import org.apache.commons.logging.Log;
//import org.mortbay.log.LogFactory;
import org.mortbay.jetty.HttpHeaders;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.mortbay.util.LineInput;
import org.mortbay.util.MultiMap;
import org.mortbay.util.StringUtil;
/* ------------------------------------------------------------ */
/** Multipart Form Data request.