mirror of
https://github.com/i2p/i2p.i2p.git
synced 2026-03-29 07:39:57 +00:00
Eepsite on Jetty 12
TODO: - FCGI - Migration - Stop/restart - Webapp deployer
This commit is contained in:
@@ -1,51 +1,6 @@
|
||||
// Contains code from Jetty 9.2.21:
|
||||
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package net.i2p.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.Collator;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.ee8.nested.ContextHandler;
|
||||
import org.eclipse.jetty.ee8.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.CombinedResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Extends DefaultServlet to set locale for the displayed time of directory listings,
|
||||
@@ -56,316 +11,10 @@ import net.i2p.data.DataHelper;
|
||||
*/
|
||||
public class I2PDefaultServlet extends DefaultServlet
|
||||
{
|
||||
// shadows of private fields in super
|
||||
private ContextHandler _contextHandler;
|
||||
private boolean _dirAllowed=true;
|
||||
private Resource _resourceBase;
|
||||
private Resource _stylesheet;
|
||||
|
||||
private static final String FORMAT = "yyyy-MM-dd HH:mm";
|
||||
|
||||
/**
|
||||
* Overridden to save local copies of dirAllowed, locale, resourceBase, and stylesheet.
|
||||
* Calls super.
|
||||
* @since Jetty 12
|
||||
*/
|
||||
@Override
|
||||
public void init()
|
||||
throws UnavailableException
|
||||
{
|
||||
super.init();
|
||||
_dirAllowed=getInitBoolean("dirAllowed",_dirAllowed);
|
||||
|
||||
String rb=getInitParameter("resourceBase");
|
||||
if (rb!=null)
|
||||
{
|
||||
try{_resourceBase = ResourceFactory.root().newResource(rb);}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new UnavailableException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String css=getInitParameter("stylesheet");
|
||||
try
|
||||
{
|
||||
if(css!=null)
|
||||
{
|
||||
_stylesheet = ResourceFactory.root().newResource(css);
|
||||
if(!_stylesheet.exists())
|
||||
{
|
||||
_stylesheet = null;
|
||||
}
|
||||
}
|
||||
if(_stylesheet == null)
|
||||
{
|
||||
_stylesheet = ResourceFactory.root().newResource(this.getClass().getResource("/jetty-dir.css"));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to save the result
|
||||
* Calls super.
|
||||
*/
|
||||
@Override
|
||||
protected ContextHandler initContextHandler(ServletContext servletContext)
|
||||
{
|
||||
ContextHandler rv = super.initContextHandler(servletContext);
|
||||
_contextHandler = rv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* copied from DefaultServlet unchanged */
|
||||
private boolean getInitBoolean(String name, boolean dft)
|
||||
{
|
||||
String value=getInitParameter(name);
|
||||
if (value==null || value.length()==0)
|
||||
return dft;
|
||||
return (value.startsWith("t")||
|
||||
value.startsWith("T")||
|
||||
value.startsWith("y")||
|
||||
value.startsWith("Y")||
|
||||
value.startsWith("1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied and modified from DefaultServlet.java.
|
||||
* Overridden to set the Locale for the dates.
|
||||
*
|
||||
* Get the resource list as a HTML directory listing.
|
||||
*/
|
||||
protected void sendDirectory(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Resource resource,
|
||||
String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
if (!_dirAllowed)
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data=null;
|
||||
String base = URIUtil.addPaths(request.getRequestURI(), "/");
|
||||
|
||||
//If the DefaultServlet has a resource base set, use it
|
||||
if (_resourceBase != null)
|
||||
{
|
||||
// handle ResourceCollection
|
||||
if (_resourceBase instanceof CombinedResource)
|
||||
resource=_resourceBase.resolve(pathInContext);
|
||||
}
|
||||
//Otherwise, try using the resource base of its enclosing context handler
|
||||
else if (_contextHandler.getBaseResource() instanceof CombinedResource)
|
||||
resource=_contextHandler.getBaseResource().resolve(pathInContext);
|
||||
|
||||
String dir = getListHTML(resource, base, pathInContext.length()>1);
|
||||
if (dir==null)
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||
"No directory");
|
||||
return;
|
||||
}
|
||||
|
||||
data=dir.getBytes("UTF-8");
|
||||
response.setContentType("text/html; charset=UTF-8");
|
||||
response.setContentLength(data.length);
|
||||
response.getOutputStream().write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied and modified from Resource.java
|
||||
* Modified to set the Locale for the dates.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
private static String getListHTML(Resource res, String base, boolean parent)
|
||||
throws IOException
|
||||
{
|
||||
base=URIUtil.canonicalPath(base);
|
||||
if (base==null || !res.isDirectory())
|
||||
return null;
|
||||
|
||||
List<Resource> ls = res.list();
|
||||
if (ls==null)
|
||||
return null;
|
||||
DataHelper.sort(ls, new FileComparator(res));
|
||||
|
||||
String decodedBase = URIUtil.decodePath(base);
|
||||
String title = "Directory: "+deTag(decodedBase);
|
||||
|
||||
StringBuilder buf=new StringBuilder(4096);
|
||||
buf.append("<HTML><HEAD>");
|
||||
buf.append("<LINK HREF=\"").append("jetty-dir.css").append("\" REL=\"stylesheet\" TYPE=\"text/css\"/><TITLE>");
|
||||
buf.append(title);
|
||||
buf.append("</TITLE></HEAD><BODY>\n<H1>");
|
||||
buf.append(title);
|
||||
buf.append("</H1>\n<TABLE BORDER=0>\n");
|
||||
|
||||
if (parent)
|
||||
{
|
||||
buf.append("<TR><TD><A HREF=\"");
|
||||
buf.append(URIUtil.addPaths(base,"../"));
|
||||
buf.append("\">Parent Directory</A></TD><TD></TD><TD></TD></TR>\n");
|
||||
}
|
||||
|
||||
String encodedBase = hrefEncodeURI(base);
|
||||
|
||||
DateFormat dfmt = new SimpleDateFormat(FORMAT, Locale.UK);
|
||||
TimeZone utc = TimeZone.getTimeZone("GMT");
|
||||
dfmt.setTimeZone(utc);
|
||||
for (Resource item : ls)
|
||||
{
|
||||
/* FIXME still needed?
|
||||
try {
|
||||
item = res.resolve(r);
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Skipping file in directory listing: " + ioe.getMessage());
|
||||
continue;
|
||||
} catch (RuntimeException re) {
|
||||
// Jetty bug, addPath() argument must be unencoded,
|
||||
// but does not escape [],so it throws an unchecked exception:
|
||||
//
|
||||
// java.nio.file.InvalidPathException:
|
||||
// Illegal character in path at index xx: file:/home/.../[test].txt: [test].txt
|
||||
// at org.eclipse.jetty.util.resource.FileResource.addPath(FileResource.java:213)
|
||||
// ...
|
||||
//
|
||||
// Catch here and continue so we show the rest of the listing,
|
||||
// and don't output the full path in the error page
|
||||
// TODO actually handle it
|
||||
System.out.println("Skipping file in directory listing: " + re.getMessage());
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
buf.append("\n<TR><TD><A HREF=\"");
|
||||
String path=URIUtil.addPaths(encodedBase,URIUtil.encodePath(item.toString()));
|
||||
|
||||
buf.append(path);
|
||||
|
||||
boolean isDir = item.isDirectory();
|
||||
if (isDir && !path.endsWith("/"))
|
||||
buf.append('/');
|
||||
|
||||
buf.append("\">");
|
||||
buf.append(deTag(item.toString()));
|
||||
buf.append("</A></TD><TD ALIGN=right>");
|
||||
if (!isDir) {
|
||||
buf.append(item.length());
|
||||
buf.append(" bytes ");
|
||||
}
|
||||
buf.append("</TD><TD>");
|
||||
if (!isDir) {
|
||||
buf.append(dfmt.format(new Date(item.lastModified().toEpochMilli())));
|
||||
buf.append(" UTC");
|
||||
}
|
||||
buf.append("</TD></TR>");
|
||||
}
|
||||
buf.append("</TABLE>\n");
|
||||
buf.append("</BODY></HTML>\n");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P
|
||||
*
|
||||
* @since 0.9.51
|
||||
*/
|
||||
private static class FileComparator implements Comparator<Resource> {
|
||||
private final Comparator<Object> _coll;
|
||||
private final Resource _base;
|
||||
|
||||
public FileComparator(Resource base) {
|
||||
_base = base;
|
||||
_coll = Collator.getInstance(Locale.US);
|
||||
}
|
||||
|
||||
public int compare(Resource ra, Resource rb) {
|
||||
try {
|
||||
boolean da = ra.isDirectory();
|
||||
boolean db = rb.isDirectory();
|
||||
if (da && !db) return -1;
|
||||
if (!da && db) return 1;
|
||||
} catch (Exception e) {
|
||||
// see above
|
||||
}
|
||||
return _coll.compare(ra.toString(), rb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied unchanged from Resource.java
|
||||
*
|
||||
* Encode any characters that could break the URI string in an HREF.
|
||||
* Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a>
|
||||
*
|
||||
* The above example would parse incorrectly on various browsers as the "<" or '"' characters
|
||||
* would end the href attribute value string prematurely.
|
||||
*
|
||||
* @param raw the raw text to encode.
|
||||
* @return the defanged text.
|
||||
*/
|
||||
private static String hrefEncodeURI(String raw)
|
||||
{
|
||||
StringBuffer buf = null;
|
||||
|
||||
loop:
|
||||
for (int i=0;i<raw.length();i++)
|
||||
{
|
||||
char c=raw.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '\'':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
buf=new StringBuffer(raw.length()<<1);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (buf==null)
|
||||
return raw;
|
||||
|
||||
for (int i=0;i<raw.length();i++)
|
||||
{
|
||||
char c=raw.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
default:
|
||||
buf.append(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied unchanged from Resource.java
|
||||
*/
|
||||
private static String deTag(String raw)
|
||||
{
|
||||
return StringUtil.sanitizeXmlString(raw);
|
||||
public I2PDefaultServlet() {
|
||||
super(new I2PResourceService());
|
||||
}
|
||||
}
|
||||
|
||||
452
apps/jetty/java/src/net/i2p/servlet/I2PResourceService.java
Normal file
452
apps/jetty/java/src/net/i2p/servlet/I2PResourceService.java
Normal file
@@ -0,0 +1,452 @@
|
||||
// Adapted from Jetty ResourceService.java and ResourceListing.java
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
package net.i2p.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.text.Collator;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.ee8.nested.ResourceService;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollators;
|
||||
import org.eclipse.jetty.util.resource.Resources;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* To customize directory listings.
|
||||
* Used by I2PDefaultServlet.
|
||||
*
|
||||
* @since Jetty 12
|
||||
*/
|
||||
public class I2PResourceService extends ResourceService {
|
||||
|
||||
private static final String FORMAT = "yyyy-MM-dd HH:mm";
|
||||
|
||||
/**
|
||||
* Copied and modified from ResourceService.java.
|
||||
* Overridden to set the Locale for the dates.
|
||||
*
|
||||
* Get the resource list as a HTML directory listing.
|
||||
*/
|
||||
@Override
|
||||
protected void sendDirectory(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Resource resource,
|
||||
String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
if (!isDirAllowed())
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data;
|
||||
String base = URIUtil.addEncodedPaths(request.getRequestURI(), "/");
|
||||
String dir = getListHTML(resource, base, pathInContext.length() > 1, request.getQueryString());
|
||||
if (dir == null)
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN,
|
||||
"No directory");
|
||||
return;
|
||||
}
|
||||
|
||||
data = dir.getBytes(StandardCharsets.UTF_8);
|
||||
response.setContentType("text/html;charset=utf-8");
|
||||
response.setContentLength(data.length);
|
||||
response.getOutputStream().write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied and modified from Resource.java (Jetty 9) / ResourceListing.java (Jetty 12).
|
||||
* Modified to set the Locale for the dates.
|
||||
*
|
||||
* 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
|
||||
* @since Jetty 12 moved from I2PDefaultServlet
|
||||
*/
|
||||
private static String getListHTML(Resource resource, String base, boolean parent, String query)
|
||||
throws IOException
|
||||
{
|
||||
// This method doesn't check aliases, so it is OK to canonicalize here.
|
||||
base = URIUtil.normalizePath(base);
|
||||
if (base == null)
|
||||
return null;
|
||||
if (!Resources.isReadableDirectory(resource))
|
||||
return null;
|
||||
|
||||
List<Resource> listing = resource.list().stream()
|
||||
.filter(distinctBy(Resource::getFileName))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
boolean sortOrderAscending = true;
|
||||
String sortColumn = "N"; // name (or "M" for Last Modified, or "S" for Size)
|
||||
|
||||
// check for query
|
||||
if (query != null)
|
||||
{
|
||||
Fields params = new Fields(true);
|
||||
UrlEncoded.decodeUtf8To(query, 0, query.length(), params);
|
||||
|
||||
String paramO = params.getValue("O");
|
||||
String paramC = params.getValue("C");
|
||||
if (StringUtil.isNotBlank(paramO))
|
||||
{
|
||||
switch (paramO)
|
||||
{
|
||||
case "A" -> sortOrderAscending = true;
|
||||
case "D" -> sortOrderAscending = false;
|
||||
}
|
||||
}
|
||||
if (StringUtil.isNotBlank(paramC))
|
||||
{
|
||||
if (paramC.equals("N") || paramC.equals("M") || paramC.equals("S"))
|
||||
{
|
||||
sortColumn = paramC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform sort
|
||||
Comparator<? super Resource> sort;
|
||||
switch (sortColumn)
|
||||
{
|
||||
case "M": sort = ResourceCollators.byLastModified(sortOrderAscending);
|
||||
break;
|
||||
case "S": sort = new SizeComparator();
|
||||
if (!sortOrderAscending)
|
||||
sort = sort.reversed();
|
||||
break;
|
||||
default: sort = new FileComparator();
|
||||
if (!sortOrderAscending)
|
||||
sort = sort.reversed();
|
||||
break;
|
||||
}
|
||||
DataHelper.sort(listing, sort);
|
||||
|
||||
String decodedBase = URIUtil.decodePath(base);
|
||||
String title = "Directory: " + deTag(decodedBase);
|
||||
|
||||
StringBuilder buf = new StringBuilder(4096);
|
||||
|
||||
// Doctype Declaration + XHTML. The spec says the encoding MUST be "utf-8" in all cases at it is ignored;
|
||||
// see: https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-charset
|
||||
buf.append("""
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
""");
|
||||
|
||||
// HTML Header
|
||||
buf.append("<head>\n");
|
||||
buf.append("<link href=\"jetty-dir.css\" rel=\"stylesheet\" />\n");
|
||||
buf.append("<title>");
|
||||
buf.append(title);
|
||||
buf.append("</title>\n");
|
||||
buf.append("</head>\n");
|
||||
|
||||
// HTML Body
|
||||
buf.append("<body>\n");
|
||||
buf.append("<h1 class=\"title\">").append(title).append("</h1>\n");
|
||||
|
||||
// HTML Table
|
||||
final String ARROW_DOWN = " ⇩";
|
||||
final String ARROW_UP = " ⇧";
|
||||
|
||||
buf.append("<table class=\"listing\">\n");
|
||||
buf.append("<thead>\n");
|
||||
|
||||
String arrow = "";
|
||||
String order = "A";
|
||||
if (sortColumn.equals("N"))
|
||||
{
|
||||
if (sortOrderAscending)
|
||||
{
|
||||
order = "D";
|
||||
arrow = ARROW_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = "A";
|
||||
arrow = ARROW_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
buf.append("<tr><th class=\"name\"><a href=\"?C=N&O=").append(order).append("\">");
|
||||
buf.append("Name").append(arrow);
|
||||
buf.append("</a></th>");
|
||||
|
||||
arrow = "";
|
||||
order = "A";
|
||||
if (sortColumn.equals("M"))
|
||||
{
|
||||
if (sortOrderAscending)
|
||||
{
|
||||
order = "D";
|
||||
arrow = ARROW_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = "A";
|
||||
arrow = ARROW_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
buf.append("<th class=\"lastmodified\"><a href=\"?C=M&O=").append(order).append("\">");
|
||||
buf.append("Last Modified (UTC)").append(arrow);
|
||||
buf.append("</a></th>");
|
||||
|
||||
arrow = "";
|
||||
order = "A";
|
||||
if (sortColumn.equals("S"))
|
||||
{
|
||||
if (sortOrderAscending)
|
||||
{
|
||||
order = "D";
|
||||
arrow = ARROW_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = "A";
|
||||
arrow = ARROW_DOWN;
|
||||
}
|
||||
}
|
||||
buf.append("<th class=\"size\"><a href=\"?C=S&O=").append(order).append("\">");
|
||||
buf.append("Size").append(arrow);
|
||||
buf.append("</a></th></tr>\n");
|
||||
buf.append("</thead>\n");
|
||||
|
||||
buf.append("<tbody>\n");
|
||||
|
||||
String encodedBase = hrefEncodeURI(base);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
// Name
|
||||
buf.append("<tr><td class=\"name\"><a href=\"");
|
||||
// TODO This produces an absolute link from the /context/<listing-dir> path, investigate if we can use relative links reliably now
|
||||
buf.append(URIUtil.addPaths(encodedBase, "../"));
|
||||
buf.append("\">Parent Directory</a></td>");
|
||||
// Last Modified
|
||||
buf.append("<td class=\"lastmodified\">-</td>");
|
||||
// Size
|
||||
buf.append("<td class=\"size\">-</td>");
|
||||
buf.append("</tr>\n");
|
||||
}
|
||||
|
||||
DateFormat dfmt = new SimpleDateFormat(FORMAT, Locale.UK);
|
||||
TimeZone utc = TimeZone.getTimeZone("GMT");
|
||||
dfmt.setTimeZone(utc);
|
||||
|
||||
for (Resource item : listing)
|
||||
{
|
||||
// Listings always return non-composite Resource entries
|
||||
String name = item.getFileName();
|
||||
if (StringUtil.isBlank(name))
|
||||
continue; // a resource either not backed by a filename (eg: MemoryResource), or has no filename (eg: a segment-less root "/")
|
||||
|
||||
// Ensure name has a slash if it's a directory
|
||||
boolean isDir = item.isDirectory();
|
||||
if (isDir && !name.endsWith("/"))
|
||||
name += "/";
|
||||
|
||||
// Name
|
||||
buf.append("<tr><td class=\"name\"><a href=\"");
|
||||
// TODO should this be a relative link?
|
||||
String path = URIUtil.addEncodedPaths(encodedBase, URIUtil.encodePath(name));
|
||||
buf.append(path);
|
||||
buf.append("\">");
|
||||
buf.append(deTag(name));
|
||||
buf.append(" </a></td>");
|
||||
|
||||
// Last Modified
|
||||
buf.append("<td class=\"lastmodified\">");
|
||||
Instant lastModified = item.lastModified();
|
||||
buf.append(dfmt.format(new Date(lastModified.toEpochMilli())));
|
||||
buf.append(" </td>");
|
||||
|
||||
// Size
|
||||
buf.append("<td class=\"size\">");
|
||||
if (isDir) {
|
||||
buf.append('-');
|
||||
} else {
|
||||
long length = item.length();
|
||||
if (length >= 0)
|
||||
{
|
||||
buf.append(String.format("%,d bytes", item.length()));
|
||||
} else {
|
||||
buf.append('-');
|
||||
}
|
||||
}
|
||||
buf.append("</td></tr>\n");
|
||||
}
|
||||
|
||||
buf.append("</tbody>\n");
|
||||
buf.append("</table>\n");
|
||||
buf.append("</body></html>\n");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static <T> Predicate<T> distinctBy(Function<? super T, Object> keyExtractor)
|
||||
{
|
||||
HashSet<Object> map = new HashSet<>();
|
||||
return t -> map.add(keyExtractor.apply(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P
|
||||
*
|
||||
* @since 0.9.51
|
||||
*/
|
||||
private static class FileComparator implements Comparator<Resource> {
|
||||
private final Comparator<Object> _coll;
|
||||
|
||||
public FileComparator() {
|
||||
_coll = Collator.getInstance(Locale.US);
|
||||
}
|
||||
|
||||
public int compare(Resource ra, Resource rb) {
|
||||
try {
|
||||
boolean da = ra.isDirectory();
|
||||
boolean db = rb.isDirectory();
|
||||
if (da && !db) return -1;
|
||||
if (!da && db) return 1;
|
||||
} catch (Exception e) {
|
||||
// see above
|
||||
}
|
||||
return _coll.compare(ra.toString(), rb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P
|
||||
*
|
||||
* @since Jetty 12
|
||||
*/
|
||||
private static class SizeComparator implements Comparator<Resource> {
|
||||
private final Comparator<Object> _coll;
|
||||
|
||||
public SizeComparator() {
|
||||
_coll = Collator.getInstance(Locale.US);
|
||||
}
|
||||
|
||||
public int compare(Resource ra, Resource rb) {
|
||||
try {
|
||||
boolean da = ra.isDirectory();
|
||||
boolean db = rb.isDirectory();
|
||||
long sa = da ? -1 : ra.length();
|
||||
long sb = db ? -1 : rb.length();
|
||||
int rv = Long.compare(sa, sb);
|
||||
if (rv != 0) return rv;
|
||||
} catch (Exception e) {
|
||||
// see above
|
||||
}
|
||||
return _coll.compare(ra.toString(), rb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied unchanged from Resource.java
|
||||
*
|
||||
* Encode any characters that could break the URI string in an HREF.
|
||||
* Such as <a href="/path/to;<script>Window.alert("XSS"+'%20'+"here");</script>">Link</a>
|
||||
*
|
||||
* The above example would parse incorrectly on various browsers as the "<" or '"' characters
|
||||
* would end the href attribute value string prematurely.
|
||||
*
|
||||
* @param raw the raw text to encode.
|
||||
* @return the defanged text.
|
||||
* @since Jetty 12 moved from I2PDefaultServlet
|
||||
*/
|
||||
private static String hrefEncodeURI(String raw)
|
||||
{
|
||||
StringBuffer buf = null;
|
||||
|
||||
loop:
|
||||
for (int i=0;i<raw.length();i++)
|
||||
{
|
||||
char c=raw.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '\'':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
buf=new StringBuffer(raw.length()<<1);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (buf==null)
|
||||
return raw;
|
||||
|
||||
for (int i=0;i<raw.length();i++)
|
||||
{
|
||||
char c=raw.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
default:
|
||||
buf.append(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied unchanged from Resource.java
|
||||
* @since Jetty 12 moved from I2PDefaultServlet
|
||||
*/
|
||||
private static String deTag(String raw)
|
||||
{
|
||||
return StringUtil.sanitizeXmlString(raw);
|
||||
}
|
||||
}
|
||||
@@ -103,11 +103,11 @@ public class WebAppConfiguration implements Configuration {
|
||||
// Only really required if started manually, but we don't know that from here
|
||||
cp = "jetty-util.jar";
|
||||
****/
|
||||
// Java 11+ fix to prevent dup contexts
|
||||
wac.setParentLoaderPriority(true);
|
||||
if (ctxPath.equals("/susidns")) {
|
||||
// Old installs don't have this in their wrapper.config classpath
|
||||
cp = "addressbook.jar";
|
||||
// Java 11+ fix to prevent dup contexts
|
||||
wac.setParentLoaderPriority(true);
|
||||
} else if (pluginDir.exists()) {
|
||||
File consoleDir = new File(pluginDir, "console");
|
||||
Properties props = RouterConsoleRunner.webAppProperties(consoleDir.getAbsolutePath());
|
||||
|
||||
@@ -13,16 +13,8 @@
|
||||
<Arg>
|
||||
<New id="GzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
|
||||
<Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="512"/></Set>
|
||||
<Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
|
||||
<Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
|
||||
<Set name="syncFlush"><Property name="jetty.gzip.syncFlush" default="false" /></Set>
|
||||
|
||||
<Set name="excludedAgentPatterns">
|
||||
<Array type="String">
|
||||
<Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>
|
||||
</Array>
|
||||
</Set>
|
||||
|
||||
<Set name="includedMethods">
|
||||
<Array type="String">
|
||||
<Item>GET</Item>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!--
|
||||
Configure a custom context for the eepsite.
|
||||
@@ -8,7 +8,7 @@ This context contains only a ServletContextHandler with a default servlet
|
||||
to serve static html files and images.
|
||||
-->
|
||||
|
||||
<Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
|
||||
<Configure class="org.eclipse.jetty.ee8.servlet.ServletContextHandler">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="resourceBase">./eepsite/docroot/</Set>
|
||||
<Call name="setInitParameter">
|
||||
@@ -20,24 +20,6 @@ to serve static html files and images.
|
||||
<Arg>org.eclipse.jetty.servlet.Default.dirAllowed</Arg>
|
||||
<Arg>true</Arg>
|
||||
</Call>
|
||||
<Call name="setMimeTypes">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.http.MimeTypes">
|
||||
<Call name="addMimeMapping">
|
||||
<Arg>sud</Arg>
|
||||
<Arg>application/zip</Arg>
|
||||
</Call>
|
||||
<Call name="addMimeMapping">
|
||||
<Arg>su2</Arg>
|
||||
<Arg>application/zip</Arg>
|
||||
</Call>
|
||||
<Call name="addMimeMapping">
|
||||
<Arg>xpi2p</Arg>
|
||||
<Arg>application/zip</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Call name="addServlet">
|
||||
<Arg>net.i2p.servlet.I2PDefaultServlet</Arg>
|
||||
<Arg>/</Arg>
|
||||
|
||||
@@ -35,27 +35,21 @@
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
|
||||
<param-name>org.eclipse.jetty.session.SessionDomain</param-name>
|
||||
<param-value>127.0.0.1</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
|
||||
<param-name>org.eclipse.jetty.session.SessionPath</param-name>
|
||||
<param-value>/</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
|
||||
<param-name>org.eclipse.jetty.session.MaxAge</param-name>
|
||||
<param-value>-1</param-value>
|
||||
</context-param>
|
||||
-->
|
||||
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.webapp.NoTLDJarPattern</param-name>
|
||||
<param-value>start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar</param-value>
|
||||
</context-param>
|
||||
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- The default servlet. -->
|
||||
@@ -112,7 +106,7 @@
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<servlet>
|
||||
<servlet-name>default</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
|
||||
<servlet-class>org.eclipse.jetty.ee8.servlet.DefaultServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>acceptRanges</param-name>
|
||||
<param-value>true</param-value>
|
||||
@@ -306,7 +300,7 @@
|
||||
<!-- Uncomment for dynamic invocation
|
||||
<servlet>
|
||||
<servlet-name>invoker</servlet-name>
|
||||
<servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
|
||||
<servlet-class>org.eclipse.jetty.ee8.servlet.Invoker</servlet-class>
|
||||
<init-param>
|
||||
<param-name>verbose</param-name>
|
||||
<param-value>false</param-value>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Mixin the RewriteHandler -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- This configuration supports Jetty 9. Do not remove this line. -->
|
||||
<!-- This configuration supports Jetty 12. Do not remove this line. -->
|
||||
|
||||
<!-- ========================================================================= -->
|
||||
<!-- If you have a 'split' directory installation, with configuration -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- This configuration supports Jetty 9. Do not remove this line. -->
|
||||
<!-- This configuration supports Jetty 12. Do not remove this line. -->
|
||||
|
||||
<!-- ========================================================================= -->
|
||||
<!-- This file configures the Jetty server. -->
|
||||
@@ -154,22 +154,11 @@
|
||||
<!-- =========================================================== -->
|
||||
<!-- Set handler Collection Structure -->
|
||||
<!-- =========================================================== -->
|
||||
<Set name="defaultHandler">
|
||||
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
|
||||
</Set>
|
||||
<Set name="handler">
|
||||
<New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
|
||||
<Set name="handlers">
|
||||
<Array type="org.eclipse.jetty.server.Handler">
|
||||
<Item>
|
||||
<New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
|
||||
</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
</New>
|
||||
<New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
|
||||
</Set>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
@@ -189,10 +178,6 @@
|
||||
<Set name="contexts">
|
||||
<Ref refid="Contexts" />
|
||||
</Set>
|
||||
<Call name="setContextAttribute">
|
||||
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
|
||||
<Arg>.*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
@@ -211,7 +196,10 @@
|
||||
<Ref refid="DeploymentManager">
|
||||
<Call name="addAppProvider">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<New class="org.eclipse.jetty.deploy.providers.ContextProvider">
|
||||
<Set name="EnvironmentName">ee8</Set>
|
||||
<Set name="parentLoaderPriority">true</Set>
|
||||
<Set name="configurationClasses" property="jetty.deploy.configurationClasses" />
|
||||
<Set name="monitoredDirName">./eepsite/contexts</Set>
|
||||
<Set name="scanInterval">120</Set>
|
||||
</New>
|
||||
@@ -235,9 +223,11 @@
|
||||
<Ref refid="DeploymentManager">
|
||||
<Call id="webappprovider" name="addAppProvider">
|
||||
<Arg>
|
||||
<New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
<New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider">
|
||||
<Set name="EnvironmentName">ee8</Set>
|
||||
<Set name="parentLoaderPriority">true</Set>
|
||||
<Set name="configurationClasses" property="jetty.deploy.configurationClasses" />
|
||||
<Set name="monitoredDirName">./eepsite/webapps</Set>
|
||||
<Set name="parentLoaderPriority">false</Set>
|
||||
<!-- this is required because Jetty can't handle jars inside wars,
|
||||
for example in php-java-bridge's JavaBridgeTemplate.war
|
||||
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=433708
|
||||
@@ -299,7 +289,6 @@
|
||||
<!-- contexts configuration (see $(jetty.home)/contexts/test.xml -->
|
||||
<!-- for an example). -->
|
||||
<!-- =========================================================== -->
|
||||
<Ref refid="RequestLog">
|
||||
<Set name="requestLog">
|
||||
<New id="RequestLogImpl" class="net.i2p.jetty.I2PRequestLog">
|
||||
<Set name="filename">./eepsite/logs/yyyy_mm_dd.request.log</Set>
|
||||
@@ -313,7 +302,6 @@
|
||||
<Set name="b64">false</Set>
|
||||
</New>
|
||||
</Set>
|
||||
</Ref>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- extra options -->
|
||||
|
||||
Reference in New Issue
Block a user