diff --git a/apps/i2pcontrol/build.xml b/apps/i2pcontrol/build.xml index d3e4883da..78e4533a3 100644 --- a/apps/i2pcontrol/build.xml +++ b/apps/i2pcontrol/build.xml @@ -21,6 +21,9 @@ + + + diff --git a/apps/i2pcontrol/java/net/i2p/i2pcontrol/HostCheckHandler.java b/apps/i2pcontrol/java/net/i2p/i2pcontrol/HostCheckHandler.java index 8f60e4bb6..f8768f9e2 100644 --- a/apps/i2pcontrol/java/net/i2p/i2pcontrol/HostCheckHandler.java +++ b/apps/i2pcontrol/java/net/i2p/i2pcontrol/HostCheckHandler.java @@ -14,8 +14,10 @@ import net.i2p.util.Log; import net.i2p.apache.http.conn.util.InetAddressUtils; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; /** * Block certain Host headers to prevent DNS rebinding attacks. @@ -28,7 +30,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper; * * @since 0.12 copied from routerconsole */ -public class HostCheckHandler extends HandlerWrapper +public class HostCheckHandler extends Handler.Wrapper { private final I2PAppContext _context; private final Set _listenHosts; @@ -57,14 +59,13 @@ public class HostCheckHandler extends HandlerWrapper /** * Block by Host header, pass everything else to the delegate. */ - public void handle(String pathInContext, - Request baseRequest, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) - throws IOException, ServletException + @Override + public boolean handle(Request request, + Response response, + Callback callback) + throws Exception { - - String host = httpRequest.getHeader("Host"); + String host = request.getHeaders().get("Host"); if (!allowHost(host)) { Log log = _context.logManager().getLog(HostCheckHandler.class); host = DataHelper.stripHTML(getHost(host)); @@ -73,11 +74,12 @@ public class HostCheckHandler extends HandlerWrapper I2PControlController.PROP_ALLOWED_HOSTS + '=' + host + "\" to I2PControl.conf and restart."; log.logAlways(Log.WARN, s); - httpResponse.sendError(403, s); - return; + Response.writeError(request, response, callback, 403, s); + callback.succeeded(); + return true; } - super.handle(pathInContext, baseRequest, httpRequest, httpResponse); + return super.handle(request, response, callback); } /** diff --git a/apps/i2pcontrol/java/net/i2p/i2pcontrol/I2PControlController.java b/apps/i2pcontrol/java/net/i2p/i2pcontrol/I2PControlController.java index 612b15606..3e769ce78 100644 --- a/apps/i2pcontrol/java/net/i2p/i2pcontrol/I2PControlController.java +++ b/apps/i2pcontrol/java/net/i2p/i2pcontrol/I2PControlController.java @@ -31,6 +31,8 @@ import net.i2p.i2pcontrol.security.SecurityManager; import net.i2p.i2pcontrol.servlets.JSONRPC2Servlet; import net.i2p.i2pcontrol.servlets.configuration.ConfigurationManager; +import org.eclipse.jetty.ee8.servlet.ServletContextHandler; +import org.eclipse.jetty.ee8.servlet.ServletHolder; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -38,8 +40,6 @@ import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.ssl.SslContextFactory; import java.io.File; @@ -238,8 +238,8 @@ public class I2PControlController implements RouterApp { Connector ssl = buildDefaultListener(server); server.addConnector(ssl); - ServletHandler sh = new ServletHandler(); - sh.addServletWithMapping(new ServletHolder(new JSONRPC2Servlet(_context, _secMan)), "/"); + ServletContextHandler sch = new ServletContextHandler(); + sch.addServlet(new ServletHolder(new JSONRPC2Servlet(_context, _secMan)), "/"); HostCheckHandler hch = new HostCheckHandler(_appContext); Set listenHosts = new HashSet(8); // fix up the allowed hosts set (see HostCheckHandler) @@ -261,8 +261,8 @@ public class I2PControlController implements RouterApp { } } hch.setListenHosts(listenHosts); - hch.setHandler(sh); - server.getServer().setHandler(hch); + hch.setHandler(sch); + server.setHandler(hch); _conf.writeConfFile(); return server; @@ -282,7 +282,8 @@ public class I2PControlController implements RouterApp { } // the keystore path and password - SslContextFactory sslFactory = new SslContextFactory(_ksp.getKeyStoreLocation()); + SslContextFactory.Server sslFactory = new SslContextFactory.Server(); + sslFactory.setKeyStorePath(_ksp.getKeyStoreLocation()); sslFactory.setKeyStorePassword(KeyStoreProvider.DEFAULT_KEYSTORE_PASSWORD); // the X.509 cert password (if not present, verifyKeyStore() returned false) sslFactory.setKeyManagerPassword(KeyStoreProvider.DEFAULT_CERTIFICATE_PASSWORD); diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index 49971b3bf..b78e34e59 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -62,6 +62,8 @@ + + diff --git a/apps/i2psnark/java/src/org/klomp/snark/standalone/HostCheckHandler.java b/apps/i2psnark/java/src/org/klomp/snark/standalone/HostCheckHandler.java index 0669355bb..768e3cba6 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/standalone/HostCheckHandler.java +++ b/apps/i2psnark/java/src/org/klomp/snark/standalone/HostCheckHandler.java @@ -13,8 +13,10 @@ import net.i2p.I2PAppContext; import net.i2p.util.Addresses; import net.i2p.util.Log; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; /** * Block certain Host headers to prevent DNS rebinding attacks. @@ -23,7 +25,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; * * @since 0.9.34 adapted from router console */ -public class HostCheckHandler extends AbstractHandler { +public class HostCheckHandler extends Handler.Abstract { private final I2PAppContext _context; private final Set _listenHosts; private static final String PROP_ALLOWED_HOSTS = "i2psnark.allowedHosts"; @@ -63,14 +65,13 @@ public class HostCheckHandler extends AbstractHandler { * redirect HTTP to HTTPS, * pass everything else to the delegate. */ - public void handle(String pathInContext, - Request baseRequest, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) - throws IOException, ServletException + @Override + public boolean handle(Request request, + Response response, + Callback callback) + throws Exception { - - String host = httpRequest.getHeader("Host"); + String host = request.getHeaders().get("Host"); if (!allowHost(host)) { Log log = _context.logManager().getLog(HostCheckHandler.class); host = getHost(host); @@ -79,10 +80,11 @@ public class HostCheckHandler extends AbstractHandler { PROP_ALLOWED_HOSTS + '=' + host + "\" in the file " + RunStandalone.APP_CONFIG_FILE.getAbsolutePath() + " and restart."; log.logAlways(Log.WARN, s); - httpResponse.sendError(403, s); - baseRequest.setHandled(true); - return; + Response.writeError(request, response, callback, 403, s); + callback.succeeded(); + return true; } + return false; } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java b/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java index d960e6fc4..5a48a590b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java +++ b/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java @@ -5,8 +5,6 @@ import java.io.File; import java.io.IOException; import java.util.Properties; -import org.eclipse.jetty.util.log.Log; - import net.i2p.I2PAppContext; import net.i2p.app.MenuCallback; import net.i2p.app.MenuHandle; @@ -44,11 +42,8 @@ public class RunStandalone { _context = new I2PAppContext(p); // Do this after we have a context // To take effect, must be set before any Jetty classes are loaded - try { - Log.setLog(new I2PLogger(_context)); - } catch (Throwable t) { - System.err.println("INFO: I2P Jetty logging class not found, logging to stdout"); - } + // https://slf4j.org/faq.html + System.setProperty("slf4j.provider", "net.i2p.jetty.I2PLoggingServiceProvider"); File base = _context.getBaseDir(); File xml = new File(base, "jetty-i2psnark.xml"); _jettyStart = new JettyStart(_context, null, new String[] { xml.getAbsolutePath() } ); diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml index 866bc1dd9..af45a9e76 100644 --- a/apps/jetty/build.xml +++ b/apps/jetty/build.xml @@ -16,10 +16,10 @@ - - + + - + @@ -154,44 +154,44 @@ start.jar: Needed for clients.config startup of eepsites jetty-util-xxx.jar: LifeCycle (base class for stuff), URIUtil (used in i2psnark) jetty-deploy, -http, -io, -security, -servlet, -webapp: All split out from main server jar in Jetty 7 - jetty-continuation-xxx.jar: Needed? Useful? + jetty-continuation-xxx.jar: Old Jetty 9, now a dummy 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 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 - javax.servlet.jsp-2.2.0.v201112011158.jar: Required API - servlet-api-3.0.jar: Required API + jetty-management: No longer included All of these are available in the Ubuntu packages libjetty-java and libjetty-extra-java --> - - - - - - - + + + + + + + + + + - - + + + + - @@ -203,6 +203,11 @@ + + + + + @@ -248,7 +253,7 @@ - + - + @@ -485,11 +490,11 @@ - + diff --git a/apps/jetty/java/src/net/i2p/jetty/I2PLogger.java b/apps/jetty/java/src/net/i2p/jetty/I2PLogger.java index 8c081d672..317106dd1 100644 --- a/apps/jetty/java/src/net/i2p/jetty/I2PLogger.java +++ b/apps/jetty/java/src/net/i2p/jetty/I2PLogger.java @@ -19,8 +19,10 @@ import java.nio.channels.ClosedChannelException; import net.i2p.I2PAppContext; import net.i2p.util.Log; +import org.slf4j.Logger; +import org.slf4j.Marker; + import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.util.log.Logger; /** * Modified from Jetty 6.1.26 StdErrLog.java and Slf4jLog.java @@ -281,4 +283,106 @@ public class I2PLogger implements Logger public void debug(String msg, long arg) { debug(msg, Long.valueOf(arg), null); } + + /** + * All of the following + * @since Jetty 12 + */ + public void debug(Marker marker, String msg) { debug(msg); } + public void debug(Marker marker, String format, Object arg) { debug(format, arg); } + public void debug(Marker marker, String format, Object... arguments) { debug(format, arguments); } + public void debug(Marker marker, String format, Object arg1, Object arg2) { debug(format, arg1, arg2); } + public void debug(Marker marker, String msg, Throwable t) { debug(msg, t); } + + public void error(Marker marker, String msg) { error(msg); } + public void error(Marker marker, String format, Object arg) { error(format, arg); } + public void error(Marker marker, String format, Object... arguments) { error(format, arguments); } + public void error(Marker marker, String format, Object arg1, Object arg2) { error(format, arg1, arg2); } + public void error(Marker marker, String msg, Throwable t) { error(msg, t); } + + public void info(Marker marker, String msg) { info(msg); } + public void info(Marker marker, String format, Object arg) { info(format, arg); } + public void info(Marker marker, String format, Object... arguments) { info(format, arguments); } + public void info(Marker marker, String format, Object arg1, Object arg2) { info(format, arg1, arg2); } + public void info(Marker marker, String msg, Throwable t) { info(msg, t); } + + public void trace(Marker marker, String msg) { trace(msg); } + public void trace(Marker marker, String format, Object arg) { trace(format, arg); } + public void trace(Marker marker, String format, Object... arguments) { trace(format, arguments); } + public void trace(Marker marker, String format, Object arg1, Object arg2) { trace(format, arg1, arg2); } + public void trace(Marker marker, String msg, Throwable t) { trace(msg, t); } + + public void warn(Marker marker, String msg) { warn(msg); } + public void warn(Marker marker, String format, Object arg) { warn(format, arg); } + public void warn(Marker marker, String format, Object... arguments) { warn(format, arguments); } + public void warn(Marker marker, String format, Object arg1, Object arg2) { warn(format, arg1, arg2); } + public void warn(Marker marker, String msg, Throwable t) { warn(msg, t); } + + public boolean isDebugEnabled(Marker marker) { return isDebugEnabled(); } + public boolean isErrorEnabled(Marker marker) { return isErrorEnabled(); } + public boolean isInfoEnabled(Marker marker) { return isInfoEnabled(); } + public boolean isTraceEnabled(Marker marker) { return isTraceEnabled(); } + public boolean isWarnEnabled(Marker marker) { return isWarnEnabled(); } + + public boolean isErrorEnabled() { return _log.shouldError(); } + public boolean isInfoEnabled() { return _log.shouldInfo(); } + public boolean isTraceEnabled() { return _log.shouldDebug(); } + public boolean isWarnEnabled() { return _log.shouldWarn(); } + + public void trace(String msg) { debug(msg); } + public void trace(String format, Object arg) { debug(format, arg); } + public void trace(String format, Object... arguments) { debug(format, arguments); } + public void trace(String format, Object arg1, Object arg2) { debug(format, arg1, arg2); } + public void trace(String msg, Throwable t) { debug(msg, t); } + + public void debug(String msg, Object arg) { debug(msg, arg, null); } + public void info(String msg, Object arg) { info(msg, arg, null); } + public void warn(String msg, Object arg) { warn(msg, arg, null); } + + public void debug(String msg) { debug(msg, null, null); } + public void info(String msg) { info(msg, null, null); } + public void warn(String msg) { warn(msg, null, null); } + + + public void error(String msg,Object arg0, Object arg1) + { + if (arg0 == null && arg1 == null) { + _log.error(msg); + } else if (arg0 != null && arg1 == null && arg0 instanceof Throwable) { + error(msg, (Throwable) arg0); + } else { + format(msg,arg0,arg1); + if (arg1 != null && arg1 instanceof Throwable) + _log.error(_buffer.toString(), (Throwable) arg1); + else + _log.error(_buffer.toString()); + } + } + + public void error(String msg) + { + _log.error(msg); + } + + public void error(String msg, Throwable th) + { + _log.error(msg, th); + } + + public void error(Throwable thrown) + { + error("", thrown); + } + + public void error(String msg, Object arg) + { + error(msg, arg, null); + } + + public void error(String msg, Object... args) + { + Object a1 = args.length > 0 ? args[0] : null; + Object a2 = args.length > 1 ? args[1] : null; + error(msg, a1, a2); + } } diff --git a/apps/jetty/java/src/net/i2p/jetty/I2PLoggingServiceProvider.java b/apps/jetty/java/src/net/i2p/jetty/I2PLoggingServiceProvider.java new file mode 100644 index 000000000..751c90c9f --- /dev/null +++ b/apps/jetty/java/src/net/i2p/jetty/I2PLoggingServiceProvider.java @@ -0,0 +1,60 @@ +package net.i2p.jetty; + +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.Logger; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.helpers.BasicMDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; +import org.slf4j.spi.MDCAdapter; + +/** + * An SLF4J Service Provider logging to router log with levels, + * replacing Jetty's Service Provider that logs to stderr + * (wrapper log). + * + * @since Jetty 12 + */ +public class I2PLoggingServiceProvider implements SLF4JServiceProvider { + private final ILoggerFactory lf; + private final IMarkerFactory mf; + private final MDCAdapter md; + + public I2PLoggingServiceProvider() { + lf = new LoggerFactory(); + mf = new BasicMarkerFactory(); + md = new BasicMDCAdapter(); + } + + public ILoggerFactory getLoggerFactory() { + return lf; + } + + public IMarkerFactory getMarkerFactory() { + return mf; + } + + public MDCAdapter getMDCAdapter() { + return md; + } + + public String getRequestedApiVersion() { + return "2.0.999"; + } + + public void initialize() {} + + private static class LoggerFactory implements ILoggerFactory { + private final Logger logger; + + public LoggerFactory() { + logger = new I2PLogger(); + logger.error("I2PLogger initialized"); + } + + public Logger getLogger(String name) { + return logger; + } + } + +} diff --git a/apps/jetty/java/src/net/i2p/jetty/I2PRequestLog.java b/apps/jetty/java/src/net/i2p/jetty/I2PRequestLog.java index c42de2acf..e5b61591f 100644 --- a/apps/jetty/java/src/net/i2p/jetty/I2PRequestLog.java +++ b/apps/jetty/java/src/net/i2p/jetty/I2PRequestLog.java @@ -17,23 +17,19 @@ package net.i2p.jetty; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; -//import java.io.Writer; // As of Jetty 9.4.15, RequestLog interface has a Writer subinterface import java.util.ArrayList; import java.util.Locale; import java.util.TimeZone; import javax.servlet.http.Cookie; -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.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. @@ -80,10 +76,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog private transient OutputStream _out; private transient OutputStream _fileOut; private transient DateCache _logDateCache; - private transient PathMap _ignorePathMap; private transient java.io.Writer _writer; - private transient ArrayList _buffers; - private transient char[] _copy; public I2PRequestLog() @@ -259,68 +252,56 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog try { - if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null) - return; - if (_fileOut == null) return; - Utf8StringBuilder u8buf; - StringBuilder buf; - synchronized(_writer) - { - int size=_buffers.size(); - u8buf = size==0?new Utf8StringBuilder(160):_buffers.remove(size-1); - buf = u8buf.getStringBuilder(); - } - - synchronized(buf) // for efficiency until we can use StringBuilder - { + StringBuilder buf = new StringBuilder(160); + if (_logServer) { - buf.append(request.getServerName()); + buf.append(Request.getServerName(request)); buf.append(' '); } String addr = null; if (_preferProxiedForAddress) { - addr = request.getHeader("X-Forwarded-For"); + addr = request.getHeaders().get("X-Forwarded-For"); } if (addr == null) { if (_b64) { - addr = request.getHeader("X-I2P-DestHash"); + addr = request.getHeaders().get("X-I2P-DestHash"); if (addr != null) addr += ".i2p"; } else { // 52chars.b32.i2p - addr = request.getHeader("X-I2P-DestB32"); + addr = request.getHeaders().get("X-I2P-DestB32"); } if (addr == null) - addr = request.getRemoteAddr(); + addr = Request.getRemoteAddr(request); } buf.append(addr); buf.append(" - "); - String user = request.getRemoteUser(); + String user = request.getHttpURI().getUser(); buf.append((user == null)? " - " : user); buf.append(" ["); if (_logDateCache!=null) - buf.append(_logDateCache.format(request.getTimeStamp())); + buf.append(_logDateCache.format(Request.getTimeStamp(request))); else //buf.append(request.getTimeStampBuffer().toString()); // TODO SimpleDateFormat or something - buf.append(request.getTimeStamp()); + buf.append(Request.getTimeStamp(request)); buf.append("] \""); buf.append(request.getMethod()); buf.append(' '); - u8buf.append(request.getRequestURI()); + buf.append(request.getHttpURI().getPathQuery()); buf.append(' '); - buf.append(request.getProtocol()); + buf.append(request.getConnectionMetaData().getProtocol()); buf.append("\" "); int status = response.getStatus(); if (status<=0) @@ -330,18 +311,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog buf.append((char)('0'+(status%10))); - long responseLength=response.getContentCount(); - // The above is what Jetty used before 9, but now - // it often (for large content?) returns 0 for non-cgi responses. - // Now, Jetty uses getLongContentLength(), but according to - // these threads it returns 0 for streaming (cgi) responses. - // So we take whichever one is nonzero, if the result was 200. - // See: - // https://dev.eclipse.org/mhonarc/lists/jetty-dev/msg02261.html - // and followups including this workaround: - // https://dev.eclipse.org/mhonarc/lists/jetty-dev/msg02267.html - if (responseLength == 0 && status == 200 && !"HEAD".equals(request.getMethod())) - responseLength = response.getLongContentLength(); + long responseLength = Response.getContentBytesWritten(response); if (responseLength >=0) { buf.append(' '); @@ -364,64 +334,30 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog else buf.append(" - "); - } if (!_extended && !_logCookies && !_logLatency) { synchronized(_writer) { buf.append(System.getProperty("line.separator", "\n")); - int l=buf.length(); - if (l>_copy.length) - l=_copy.length; - buf.getChars(0,l,_copy,0); - _writer.write(_copy,0,l); + _writer.write(buf.toString()); _writer.flush(); - u8buf.reset(); - _buffers.add(u8buf); } } else { synchronized(_writer) { - int l=buf.length(); - if (l>_copy.length) - l=_copy.length; - buf.getChars(0,l,_copy,0); - _writer.write(_copy,0,l); - u8buf.reset(); - _buffers.add(u8buf); + _writer.write(buf.toString()); // TODO do outside synchronized scope if (_extended) logExtended(request, response, _writer); - // TODO do outside synchronized scope - if (_logCookies) - { - Cookie[] cookies = request.getCookies(); - if (cookies == null || cookies.length == 0) - _writer.write(" -"); - else - { - _writer.write(" \""); - for (int i = 0; i < cookies.length; i++) - { - if (i != 0) - _writer.write(';'); - _writer.write(cookies[i].getName()); - _writer.write('='); - _writer.write(cookies[i].getValue()); - } - _writer.write('\"'); - } - } - if (_logLatency) { _writer.write(' '); - _writer.write(Long.toString(System.currentTimeMillis() - request.getTimeStamp())); + _writer.write(Long.toString(System.currentTimeMillis() - Request.getTimeStamp(request))); } _writer.write(System.getProperty("line.separator", "\n")); @@ -431,7 +367,8 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog } catch (IOException e) { - Log.getLogger((String)null).warn(e); + System.out.println(e.toString()); + e.printStackTrace(); } } @@ -441,7 +378,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog Response response, java.io.Writer writer) throws IOException { - String referer = request.getHeader("Referer"); + String referer = request.getHeaders().get("Referer"); if (referer == null) writer.write("\"-\" "); else @@ -451,7 +388,7 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog writer.write("\" "); } - String agent = request.getHeader("User-Agent"); + String agent = request.getHeaders().get("User-Agent"); if (agent == null) writer.write("\"-\" "); else @@ -474,25 +411,13 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog { _fileOut = new RolloverFileOutputStream(_filename,_append,_retainDays,TimeZone.getTimeZone(_logTimeZone),_filenameDateFormat,null); _closeOut = true; - Log.getLogger((String)null).info("Opened "+getDatedFilename()); } else _fileOut = System.err; _out = _fileOut; - if (_ignorePaths != null && _ignorePaths.length > 0) - { - _ignorePathMap = new PathMap(); - for (int i = 0; i < _ignorePaths.length; i++) - _ignorePathMap.put(_ignorePaths[i], _ignorePaths[i]); - } - else - _ignorePathMap = null; - _writer = new OutputStreamWriter(_out, "UTF-8"); - _buffers = new ArrayList(); - _copy = new char[1024]; super.doStart(); } @@ -500,17 +425,15 @@ public class I2PRequestLog extends AbstractLifeCycle implements RequestLog protected void doStop() throws Exception { super.doStop(); - try {if (_writer != null) _writer.flush();} catch (IOException e) {Log.getLogger((String)null).ignore(e);} + try {if (_writer != null) _writer.flush();} catch (IOException e) {} if (_out != null && _closeOut) - try {_out.close();} catch (IOException e) {Log.getLogger((String)null).ignore(e);} + try {_out.close();} catch (IOException e) {} _out = null; _fileOut = null; _closeOut = false; _logDateCache = null; _writer = null; - _buffers = null; - _copy = null; } /* ------------------------------------------------------------ */ diff --git a/apps/jetty/java/src/net/i2p/jetty/JettyStart.java b/apps/jetty/java/src/net/i2p/jetty/JettyStart.java index 69fb55f73..5fee0a644 100644 --- a/apps/jetty/java/src/net/i2p/jetty/JettyStart.java +++ b/apps/jetty/java/src/net/i2p/jetty/JettyStart.java @@ -40,8 +40,10 @@ import net.i2p.util.VersionComparator; import org.eclipse.jetty.server.AbstractNetworkConnector; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.util.resource.ResourceFactory; import org.eclipse.jetty.xml.XmlConfiguration; /** @@ -141,7 +143,7 @@ public class JettyStart implements ClientApp { } } else { URL configUrl = f.toURI().toURL(); - XmlConfiguration configuration = new XmlConfiguration(configUrl); + XmlConfiguration configuration = new XmlConfiguration(ResourceFactory.root().newResource(configUrl)); if (last!=null) configuration.getIdMap().putAll(last.getIdMap()); if (properties.size()>0) { @@ -181,7 +183,8 @@ public class JettyStart implements ClientApp { if (!lc.isRunning()) { if (lc instanceof Server) { Server server = (Server) lc; - server.insertHandler(new XI2PLocationFilter()); + // FIXME + //server.insertHandler(new XI2PLocationFilter()); } try { lc.start(); diff --git a/apps/jetty/java/src/net/i2p/jetty/JettyXmlConfigurationParser.java b/apps/jetty/java/src/net/i2p/jetty/JettyXmlConfigurationParser.java index 23461720a..36582d2af 100644 --- a/apps/jetty/java/src/net/i2p/jetty/JettyXmlConfigurationParser.java +++ b/apps/jetty/java/src/net/i2p/jetty/JettyXmlConfigurationParser.java @@ -43,25 +43,6 @@ public class JettyXmlConfigurationParser private static XmlParser initParser() { XmlParser parser = new XmlParser(); - URL config60 = Loader.getResource(XmlConfiguration.class, "org/eclipse/jetty/xml/configure_6_0.dtd"); - URL config76 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_7_6.dtd"); - URL config90 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_0.dtd"); - parser.redirectEntity("configure.dtd",config90); - parser.redirectEntity("configure_1_0.dtd",config60); - parser.redirectEntity("configure_1_1.dtd",config60); - parser.redirectEntity("configure_1_2.dtd",config60); - parser.redirectEntity("configure_1_3.dtd",config60); - parser.redirectEntity("configure_6_0.dtd",config60); - parser.redirectEntity("configure_7_6.dtd",config76); - parser.redirectEntity("configure_9_0.dtd",config90); - - parser.redirectEntity("http://jetty.mortbay.org/configure.dtd",config90); - parser.redirectEntity("http://jetty.eclipse.org/configure.dtd",config90); - parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd",config90); - - parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN",config90); - parser.redirectEntity("-//Jetty//Configure//EN",config90); - return parser; } diff --git a/apps/jetty/java/src/net/i2p/servlet/I2PDefaultServlet.java b/apps/jetty/java/src/net/i2p/servlet/I2PDefaultServlet.java index 4ad2e890e..a5c50ec60 100644 --- a/apps/jetty/java/src/net/i2p/servlet/I2PDefaultServlet.java +++ b/apps/jetty/java/src/net/i2p/servlet/I2PDefaultServlet.java @@ -27,6 +27,7 @@ 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; @@ -35,12 +36,13 @@ import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.servlet.DefaultServlet; +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.ResourceCollection; +import org.eclipse.jetty.util.resource.ResourceFactory; import net.i2p.data.DataHelper; @@ -76,7 +78,7 @@ public class I2PDefaultServlet extends DefaultServlet String rb=getInitParameter("resourceBase"); if (rb!=null) { - try{_resourceBase=_contextHandler.newResource(rb);} + try{_resourceBase = ResourceFactory.root().newResource(rb);} catch (Exception e) { throw new UnavailableException(e.toString()); @@ -88,7 +90,7 @@ public class I2PDefaultServlet extends DefaultServlet { if(css!=null) { - _stylesheet = Resource.newResource(css); + _stylesheet = ResourceFactory.root().newResource(css); if(!_stylesheet.exists()) { _stylesheet = null; @@ -96,7 +98,7 @@ public class I2PDefaultServlet extends DefaultServlet } if(_stylesheet == null) { - _stylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css")); + _stylesheet = ResourceFactory.root().newResource(this.getClass().getResource("/jetty-dir.css")); } } catch(Exception e) @@ -135,7 +137,6 @@ public class I2PDefaultServlet extends DefaultServlet * * Get the resource list as a HTML directory listing. */ - @Override protected void sendDirectory(HttpServletRequest request, HttpServletResponse response, Resource resource, @@ -149,18 +150,18 @@ public class I2PDefaultServlet extends DefaultServlet } byte[] data=null; - String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH); + String base = URIUtil.addPaths(request.getRequestURI(), "/"); //If the DefaultServlet has a resource base set, use it if (_resourceBase != null) { // handle ResourceCollection - if (_resourceBase instanceof ResourceCollection) - resource=_resourceBase.addPath(pathInContext); + if (_resourceBase instanceof CombinedResource) + resource=_resourceBase.resolve(pathInContext); } //Otherwise, try using the resource base of its enclosing context handler - else if (_contextHandler.getBaseResource() instanceof ResourceCollection) - resource=_contextHandler.getBaseResource().addPath(pathInContext); + else if (_contextHandler.getBaseResource() instanceof CombinedResource) + resource=_contextHandler.getBaseResource().resolve(pathInContext); String dir = getListHTML(resource, base, pathInContext.length()>1); if (dir==null) @@ -192,7 +193,7 @@ public class I2PDefaultServlet extends DefaultServlet if (base==null || !res.isDirectory()) return null; - String[] ls = res.list(); + List ls = res.list(); if (ls==null) return null; DataHelper.sort(ls, new FileComparator(res)); @@ -220,11 +221,11 @@ public class I2PDefaultServlet extends DefaultServlet DateFormat dfmt = new SimpleDateFormat(FORMAT, Locale.UK); TimeZone utc = TimeZone.getTimeZone("GMT"); dfmt.setTimeZone(utc); - for (int i=0 ; i< ls.length ; i++) + for (Resource item : ls) { - Resource item; +/* FIXME still needed? try { - item = res.addPath(ls[i]); + item = res.resolve(r); } catch (IOException ioe) { System.out.println("Skipping file in directory listing: " + ioe.getMessage()); continue; @@ -243,18 +244,19 @@ public class I2PDefaultServlet extends DefaultServlet System.out.println("Skipping file in directory listing: " + re.getMessage()); continue; } +*/ buf.append("\n"); - buf.append(deTag(ls[i])); + buf.append(deTag(item.toString())); buf.append(""); if (!isDir) { buf.append(item.length()); @@ -262,7 +264,7 @@ public class I2PDefaultServlet extends DefaultServlet } buf.append(""); if (!isDir) { - buf.append(dfmt.format(new Date(item.lastModified()))); + buf.append(dfmt.format(new Date(item.lastModified().toEpochMilli()))); buf.append(" UTC"); } buf.append(""); @@ -278,7 +280,7 @@ public class I2PDefaultServlet extends DefaultServlet * * @since 0.9.51 */ - private static class FileComparator implements Comparator { + private static class FileComparator implements Comparator { private final Comparator _coll; private final Resource _base; @@ -287,10 +289,8 @@ public class I2PDefaultServlet extends DefaultServlet _coll = Collator.getInstance(Locale.US); } - public int compare(String a, String b) { + public int compare(Resource ra, Resource rb) { try { - Resource ra = _base.addPath(a); - Resource rb = _base.addPath(b); boolean da = ra.isDirectory(); boolean db = rb.isDirectory(); if (da && !db) return -1; @@ -298,7 +298,7 @@ public class I2PDefaultServlet extends DefaultServlet } catch (Exception e) { // see above } - return _coll.compare(a, b); + return _coll.compare(ra.toString(), rb.toString()); } } diff --git a/apps/jetty/java/src/net/i2p/servlet/WebAppProviderConfiguration.java b/apps/jetty/java/src/net/i2p/servlet/WebAppProviderConfiguration.java index 06eafd36d..a8c908c6f 100644 --- a/apps/jetty/java/src/net/i2p/servlet/WebAppProviderConfiguration.java +++ b/apps/jetty/java/src/net/i2p/servlet/WebAppProviderConfiguration.java @@ -1,9 +1,9 @@ package net.i2p.servlet; import org.apache.tomcat.SimpleInstanceManager; -import org.eclipse.jetty.deploy.providers.WebAppProvider; -import org.eclipse.jetty.webapp.Configuration; -import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.deploy.providers.ContextProvider; +import org.eclipse.jetty.ee8.webapp.Configuration; +import org.eclipse.jetty.ee8.webapp.WebAppContext; import net.i2p.I2PAppContext; @@ -22,8 +22,10 @@ public class WebAppProviderConfiguration { * Modified from routerconsole WebAppStarter. * MUST be called from jetty.xml after the WebAppProvider is created. */ - public static void configure(WebAppProvider wap) { - String[] classNames = WebAppContext.getDefaultConfigurationClasses(); + public static void configure(ContextProvider wap) { + // Not in Jetty 12 but these are the two defaults + //String[] classNames = WebAppContext.getDefaultConfigurationClasses(); + String[] classNames = { "org.eclipse.jetty.ee8.webapp.WebXMLConfiguration", "org.eclipse.jetty.ee8.webapp.JettyWebXMLConfiguration" }; int sz = classNames.length; String[] newClassNames = new String[sz + 1]; for (int j = 0; j < sz; j++) { @@ -34,7 +36,8 @@ public class WebAppProviderConfiguration { // set the temp dir while we're at it, // so the extracted wars don't end up in /tmp - wap.setTempDir(I2PAppContext.getGlobalContext().getTempDir()); + // FIXME + //wap.setTempDir(I2PAppContext.getGlobalContext().getTempDir()); } public static class WAPConfiguration implements Configuration { @@ -54,5 +57,15 @@ public class WebAppProviderConfiguration { public void preConfigure(WebAppContext context) {} public void postConfigure(WebAppContext context) {} + + /** + * @since Jetty 12 + */ + public boolean abort(WebAppContext context) { return false; } + + /** + * @since Jetty 12 + */ + public boolean isEnabledByDefault() { return true; } } } diff --git a/apps/jetty/java/src/net/i2p/servlet/filters/XI2PLocationFilter.java b/apps/jetty/java/src/net/i2p/servlet/filters/XI2PLocationFilter.java index 251539e37..986cadbaa 100644 --- a/apps/jetty/java/src/net/i2p/servlet/filters/XI2PLocationFilter.java +++ b/apps/jetty/java/src/net/i2p/servlet/filters/XI2PLocationFilter.java @@ -13,8 +13,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.ee8.nested.Request; +import org.eclipse.jetty.ee8.nested.HandlerWrapper; import net.i2p.I2PAppContext; import net.i2p.I2PException; diff --git a/apps/jetty/patches/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java b/apps/jetty/patches/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java deleted file mode 100644 index f1cdd0f96..000000000 --- a/apps/jetty/patches/jetty-util/src/main/java/org/eclipse/jetty/util/JavaVersion.java +++ /dev/null @@ -1,153 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -/** - * Java Version Utility class. - * Parses java versions to extract a consistent set of version parts - */ -public class JavaVersion -{ - /** - * Context attribute that can be set to target a different version of the jvm than the current runtime. - * Acceptable values should correspond to those returned by JavaVersion.getPlatform(). - */ - public static final String JAVA_TARGET_PLATFORM = "org.eclipse.jetty.javaTargetPlatform"; - - public static final JavaVersion VERSION = parse(System.getProperty("java.version")); - - public static JavaVersion parse(String v) - { - // $VNUM is a dot-separated list of integers of arbitrary length - String[] split = v.split("[^0-9]"); - int len = Math.min(split.length, 3); - int[] version = new int[len]; - for (int i = 0; i < len; i++) - { - try - { - version[i] = Integer.parseInt(split[i]); - } - catch (Throwable e) - { - len = i - 1; - break; - } - } - - return new JavaVersion( - v, - (version[0] >= 9 || len == 1) ? version[0] : version[1], - version[0], - len > 1 ? version[1] : 0, - len > 2 ? version[2] : 0); - } - - private final String version; - private final int platform; - private final int major; - private final int minor; - private final int micro; - - private JavaVersion(String version, int platform, int major, int minor, int micro) - { - this.version = version; - this.platform = platform; - this.major = major; - this.minor = minor; - this.micro = micro; - } - - /** - * @return the string from which this JavaVersion was created - */ - public String getVersion() - { - return version; - } - - /** - * Returns the Java Platform version, such as {@code 8} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4. - * - * @return the Java Platform version - */ - public int getPlatform() - { - return platform; - } - - /** - * Returns the major number version, such as {@code 1} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4. - * - * @return the major number version - */ - public int getMajor() - { - return major; - } - - /** - * Returns the minor number version, such as {@code 8} for JDK 1.8.0_92 and {@code 2} for JDK 9.2.4. - * - * @return the minor number version - */ - public int getMinor() - { - return minor; - } - - /** - * Returns the micro number version (aka security number), such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4. - * - * @return the micro number version - */ - public int getMicro() - { - return micro; - } - - /** - * Returns the update number version, such as {@code 92} for JDK 1.8.0_92 and {@code 0} for JDK 9.2.4. - * - * @return the update number version - */ - @Deprecated - public int getUpdate() - { - return 0; - } - - /** - * Returns the remaining string after the version numbers, such as {@code -internal} for - * JDK 1.8.0_92-internal and {@code -ea} for JDK 9-ea, or {@code +13} for JDK 9.2.4+13. - * - * @return the remaining string after the version numbers - */ - @Deprecated - public String getSuffix() - { - return null; - } - - @Override - public String toString() - { - return version; - } -} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/HostCheckHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/HostCheckHandler.java index aad652084..ad58f1560 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/HostCheckHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/HostCheckHandler.java @@ -4,10 +4,6 @@ import java.io.IOException; import java.util.HashSet; import java.util.Set; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.util.Addresses; @@ -15,7 +11,9 @@ import net.i2p.util.Log; import net.i2p.util.PortMapper; import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.eclipse.jetty.util.Callback; /** * Block certain Host headers to prevent DNS rebinding attacks. @@ -75,14 +73,13 @@ public class HostCheckHandler extends GzipHandler * redirect HTTP to HTTPS, * pass everything else to the delegate. */ - public void handle(String pathInContext, - Request baseRequest, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) - throws IOException, ServletException + @Override + public boolean handle(Request request, + Response response, + Callback callback) + throws Exception { - - String host = httpRequest.getHeader("Host"); + String host = request.getHeaders().get("Host"); if (!allowHost(host)) { Log log = _context.logManager().getLog(HostCheckHandler.class); host = DataHelper.stripHTML(getHost(host)); @@ -91,29 +88,28 @@ public class HostCheckHandler extends GzipHandler " add the line \"" + RouterConsoleRunner.PROP_ALLOWED_HOSTS + '=' + host + "\"\n" + " to advanced configuration and restart."; log.logAlways(Log.WARN, s); - httpResponse.sendError(403, s); - baseRequest.setHandled(true); - return; + Response.writeError(request, response, callback, 403, s); + return true; } // redirect HTTP to HTTPS if available, AND: // either 1) PROP_REDIRECT is set to true; // or 2) PROP_REDIRECT is unset and the Upgrade-Insecure-Requests request header is set // https://w3c.github.io/webappsec-upgrade-insecure-requests/ - if (!httpRequest.isSecure()) { + if (!request.isSecure()) { int httpsPort = _portMapper.getPort(PortMapper.SVC_HTTPS_CONSOLE); - if (httpsPort > 0 && httpRequest.getLocalPort() != httpsPort) { + if (httpsPort > 0 && Request.getLocalPort(request) != httpsPort) { String redir = _context.getProperty(PROP_REDIRECT); if (Boolean.parseBoolean(redir) || - (redir == null && "1".equals(httpRequest.getHeader("Upgrade-Insecure-Requests")))) { - sendRedirect(httpsPort, httpRequest, httpResponse); - baseRequest.setHandled(true); - return; + (redir == null && "1".equals(request.getHeaders().get("Upgrade-Insecure-Requests")))) { + sendRedirect(httpsPort, request, response); + callback.succeeded(); + return true; } } } - super.handle(pathInContext, baseRequest, httpRequest, httpResponse); + return super.handle(request, response, callback); } /** @@ -172,11 +168,11 @@ public class HostCheckHandler extends GzipHandler * * @since 0.9.34 */ - private static void sendRedirect(int httpsPort, HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException { + private static void sendRedirect(int httpsPort, Request request, + Response response) throws IOException { StringBuilder buf = new StringBuilder(64); buf.append("https://"); - String name = httpRequest.getServerName(); + String name = Request.getServerName(request); boolean ipv6 = name.indexOf(':') >= 0 && !name.startsWith("["); if (ipv6) buf.append('['); @@ -184,14 +180,13 @@ public class HostCheckHandler extends GzipHandler if (ipv6) buf.append(']'); buf.append(':').append(httpsPort) - .append(httpRequest.getRequestURI()); - String q = httpRequest.getQueryString(); + .append(request.getHttpURI().getPath()); + String q = request.getHttpURI().getQuery(); if (q != null) buf.append('?').append(q); - httpResponse.setHeader("Location", buf.toString()); + response.getHeaders().put("Location", buf.toString()); // https://w3c.github.io/webappsec-upgrade-insecure-requests/ - httpResponse.setHeader("Vary", "Upgrade-Insecure-Requests"); - httpResponse.setStatus(307); - httpResponse.getOutputStream().close(); + response.getHeaders().put("Vary", "Upgrade-Insecure-Requests"); + response.setStatus(307); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java index d42287895..04460f4cb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java @@ -11,11 +11,14 @@ import javax.servlet.http.HttpServletResponse; import net.i2p.I2PAppContext; +import org.eclipse.jetty.ee8.nested.SessionHandler; +import org.eclipse.jetty.ee8.servlet.ServletHandler; +import org.eclipse.jetty.ee8.webapp.WebAppContext; +import org.eclipse.jetty.http.pathmap.MatchedResource; +import org.eclipse.jetty.server.Handler; 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; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; /** * Convert foo.jsp to foo_xx.jsp for language xx. @@ -26,7 +29,7 @@ import org.eclipse.jetty.webapp.WebAppContext; * * @author zzz */ -public class LocaleWebAppHandler extends HandlerWrapper +public class LocaleWebAppHandler extends Handler.Wrapper { private final I2PAppContext _context; private final WebAppContext _wac; @@ -43,24 +46,24 @@ public class LocaleWebAppHandler extends HandlerWrapper _wac.setServletHandler(servletHandler); setHandler(_wac); } - + /** * Handle foo.jsp by converting to foo_xx.jsp * for language xx, where xx is the language for the default locale, * or as specified in the routerconsole.lang property. * Unless language == "en". */ - public void handle(String pathInContext, - Request baseRequest, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) - throws IOException, ServletException + public boolean handle(Request request, + Response response, + Callback callback) + throws Exception { - + String pathInContext = Request.getPathInContext(request); + String newPath = pathInContext; // transparent rewriting if (pathInContext.equals("/") || pathInContext.equals("/index.html")) { // home page - pathInContext = "/index.jsp"; + newPath = "/index.jsp"; } else if (pathInContext.equals("/favicon.ico")) { // pass thru unchanged } else if (pathInContext.indexOf('/', 1) < 0 && @@ -68,11 +71,10 @@ public class LocaleWebAppHandler extends HandlerWrapper (!pathInContext.endsWith(".log")) && (!pathInContext.endsWith(".txt"))) { // add .jsp to pages at top level - pathInContext += ".jsp"; + newPath += ".jsp"; } //System.err.println("Path: " + pathInContext); - String newPath = pathInContext; //if (pathInContext.endsWith(".jsp")) { // We only ended up doing this for help.jsp, so save some effort // unless we translate more pages like this @@ -87,9 +89,9 @@ public class LocaleWebAppHandler extends HandlerWrapper String testPath = pathInContext.substring(0, len - 4) + '_' + lang + ".jsp"; // Do we have a servlet for the new path that isn't the catchall *.jsp? @SuppressWarnings("rawtypes") - Map.Entry servlet = _wac.getServletHandler().getHolderEntry(testPath); + MatchedResource servlet = _wac.getServletHandler().getMatchedServlet(testPath); if (servlet != null) { - String servletPath = (String) servlet.getKey(); + String servletPath = servlet.getPathSpec().getDeclaration(); if (servletPath != null && !servletPath.startsWith("*")) { // success!! //System.err.println("Servlet is: " + servletPath); @@ -99,14 +101,20 @@ public class LocaleWebAppHandler extends HandlerWrapper } } } else if (pathInContext.startsWith("/js/")) { + // https://stackoverflow.com/questions/78878330/how-to-set-encoding-for-httpservletrequest-and-httpservletresponse-in-jetty12-t // war internal - httpResponse.setCharacterEncoding("ISO-8859-1"); + //response.setCharacterEncoding("ISO-8859-1"); + // probably not doing anything + response.getHeaders().put("Content-Type", "text/javascript;charset=iso-8859-1"); } else if (pathInContext.endsWith(".css")) { // war internal - httpResponse.setCharacterEncoding("UTF-8"); + //response.setCharacterEncoding("UTF-8"); + response.getHeaders().put("Content-Type", "text/css;charset=utf-8"); } //System.err.println("New path: " + newPath); - super.handle(newPath, baseRequest, httpRequest, httpResponse); + if (!newPath.equals(pathInContext)) + request = Request.serveAs(request, Request.newHttpURIFrom(request, newPath)); + return super.handle(request, response, callback); //System.err.println("Was handled? " + httpRequest.isHandled()); } @@ -152,4 +160,11 @@ public class LocaleWebAppHandler extends HandlerWrapper context.setInitParameter((String)e.getKey(), (String)e.getValue()); } } + + /** + * @since Jetty 12 + */ + public WebAppContext getWebAppContext() { + return _wac; + } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index b456e502a..5c273edd0 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -22,7 +22,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.StringTokenizer; import java.util.concurrent.LinkedBlockingQueue; -import javax.servlet.ServletRequest; +import java.util.function.Function; import net.i2p.I2PAppContext; import net.i2p.app.ClientApp; @@ -46,34 +46,38 @@ import net.i2p.util.SecureDirectory; import net.i2p.util.I2PSSLSocketFactory; import net.i2p.util.SystemVersion; +import org.eclipse.jetty.ee8.nested.ServletConstraint; +import org.eclipse.jetty.ee8.security.ConstraintMapping; +import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler; +import org.eclipse.jetty.ee8.security.SecurityHandler; +import org.eclipse.jetty.ee8.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.ee8.security.authentication.DigestAuthenticator; +import org.eclipse.jetty.ee8.security.authentication.LoginAuthenticator; +import org.eclipse.jetty.ee8.servlet.ServletHandler; +import org.eclipse.jetty.ee8.servlet.ServletHolder; +import org.eclipse.jetty.ee8.webapp.WebAppContext; +import org.eclipse.jetty.security.Constraint; import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.security.authentication.DigestAuthenticator; -import org.eclipse.jetty.security.authentication.LoginAuthenticator; +import org.eclipse.jetty.security.UserIdentity; +import org.eclipse.jetty.security.UserStore; import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.CustomRequestLog; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.NCSARequestLog; +import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.Session; import org.eclipse.jetty.server.SslConnectionFactory; 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.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.webapp.WebAppContext; -import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.resource.ResourceFactory; +import org.eclipse.jetty.util.resource.URLResourceFactory; import org.eclipse.jetty.util.security.Credential; import org.eclipse.jetty.util.security.Credential.MD5; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -91,15 +95,8 @@ public class RouterConsoleRunner implements RouterApp { static { // To take effect, must be set before any Jetty classes are loaded - try { - Log.setLog(new I2PLogger()); - } catch (Throwable t) { - System.err.println("INFO: I2P Jetty logging class not found, logging to wrapper log"); - } - // This way it doesn't try to load Slf4jLog first - // This causes an NPE in AbstractLifeCycle - // http://dev.eclipse.org/mhonarc/lists/jetty-users/msg02587.html - //System.setProperty("org.eclipse.jetty.util.log.class", "net.i2p.jetty.I2PLogger"); + // https://slf4j.org/faq.html + System.setProperty("slf4j.provider", "net.i2p.jetty.I2PLoggingServiceProvider"); } private final RouterContext _context; @@ -501,12 +498,10 @@ public class RouterConsoleRunner implements RouterApp { _server = new Server(qtp); //} - HandlerCollection hColl = new HandlerCollection(); + Handler.Sequence hColl = new Handler.Sequence(); ContextHandlerCollection chColl = new ContextHandlerCollection(); HostCheckHandler chCollWrapper = new HostCheckHandler(_context); chCollWrapper.setHandler(chColl); - // gone in Jetty 7 - //_server.addHandler(hColl); _server.setHandler(hColl); hColl.addHandler(chCollWrapper); hColl.addHandler(new DefaultHandler()); @@ -517,9 +512,7 @@ public class RouterConsoleRunner implements RouterApp { if (!logFile.isAbsolute()) logFile = new File(_context.getLogDir(), "logs/" + log); try { - RequestLogHandler rhl = new RequestLogHandler(); - rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath())); - hColl.addHandler(rhl); + _server.setRequestLog(new CustomRequestLog(logFile.toString(), CustomRequestLog.NCSA_FORMAT)); } catch (Exception ioe) { System.err.println("ERROR: Unable to create Jetty log: " + ioe); } @@ -544,7 +537,7 @@ public class RouterConsoleRunner implements RouterApp { _webAppsDir += '/'; Set listenHosts = new HashSet(8); - HandlerWrapper rootWebApp = null; + LocaleWebAppHandler rootWebApp = null; ServletHandler rootServletHandler = null; List connectors = new ArrayList(4); try { @@ -644,7 +637,8 @@ public class RouterConsoleRunner implements RouterApp { } if (verifyKeyStore(keyStore, altNames)) { // the keystore path and password - SslContextFactory sslFactory = new SslContextFactory(keyStore.getAbsolutePath()); + SslContextFactory.Server sslFactory = new SslContextFactory.Server(); + sslFactory.setKeyStorePath(keyStore.getAbsolutePath()); sslFactory.setKeyStorePassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD)); // the X.509 cert password (if not present, verifyKeyStore() returned false) sslFactory.setKeyManagerPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork")); @@ -735,11 +729,11 @@ public class RouterConsoleRunner implements RouterApp { // Got a clue from this ancient post for Tomcat 6: // https://bz.apache.org/bugzilla/show_bug.cgi?id=39804 // see also apps/jetty/build.xml - Class.forName("org.eclipse.jetty.apache.jsp.JettyJasperInitializer"); + Class.forName("org.eclipse.jetty.ee8.apache.jsp.JettyJasperInitializer"); } catch (ClassNotFoundException cnfe) { System.err.println("Warning: JettyJasperInitializer not found"); } - WebAppContext wac = (WebAppContext)(rootWebApp.getHandler()); + WebAppContext wac = rootWebApp.getWebAppContext(); initialize(_context, wac); WebAppStarter.setWebAppConfiguration(wac, false); chColl.addHandler(rootWebApp); @@ -772,7 +766,10 @@ public class RouterConsoleRunner implements RouterApp { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=364936 // WARN:oejw.WebAppContext:Failed startup of context o.e.j.w.WebAppContext{/,jar:file:/.../webapps/routerconsole.war!/},/.../webapps/routerconsole.war // java.lang.IllegalStateException: zip file closed - Resource.setDefaultUseCaches(false); + // FIXME + //URLResourceFactory urlrf = new URLResourceFactory(); + //urlrf.setUseCaches(false); + //ResourceFactory.registerResourceFactory("jar", urlrf); try { // start does a mapContexts() _server.start(); @@ -994,6 +991,8 @@ public class RouterConsoleRunner implements RouterApp { String rlm = isBasic ? PROMETHEUS_REALM : JETTY_REALM; HashLoginService realm = new CustomHashLoginService(rlm, context.getContextPath(), ctx.logManager().getLog(RouterConsoleRunner.class)); + UserStore userStore = new UserStore(); + realm.setUserStore(userStore); sec.setLoginService(realm); LoginAuthenticator auth = isBasic ? basicAuthenticator : authenticator; sec.setAuthenticator(auth); @@ -1003,8 +1002,8 @@ public class RouterConsoleRunner implements RouterApp { String pw = e.getValue(); // for basic, the password will be the md5 hash itself Credential cred = Credential.getCredential(isBasic ? pw : MD5_CREDENTIAL_TYPE + pw); - realm.putUser(user, cred, role); - Constraint constraint = new Constraint(user, JETTY_ROLE); + userStore.addUser(user, cred, role); + ServletConstraint constraint = new ServletConstraint(user, JETTY_ROLE); constraint.setAuthenticate(true); ConstraintMapping cm = new ConstraintMapping(); cm.setConstraint(constraint); @@ -1023,8 +1022,8 @@ public class RouterConsoleRunner implements RouterApp { try { // each char truncated to 8 bytes String user2 = new String(b2, "ISO-8859-1"); - realm.putUser(user2, cred, role); - constraint = new Constraint(user2, JETTY_ROLE); + userStore.addUser(user2, cred, role); + constraint = new ServletConstraint(user2, JETTY_ROLE); constraint.setAuthenticate(true); cm = new ConstraintMapping(); cm.setConstraint(constraint); @@ -1034,8 +1033,8 @@ public class RouterConsoleRunner implements RouterApp { // each UTF-8 byte as a char // this is what chrome does String user3 = new String(b1, "ISO-8859-1"); - realm.putUser(user3, cred, role); - constraint = new Constraint(user3, JETTY_ROLE); + userStore.addUser(user3, cred, role); + constraint = new ServletConstraint(user2, JETTY_ROLE); constraint.setAuthenticate(true); cm = new ConstraintMapping(); cm.setConstraint(constraint); @@ -1057,7 +1056,7 @@ public class RouterConsoleRunner implements RouterApp { // See also: // http://old.nabble.com/Disable-HTTP-TRACE-in-Jetty-5.x-td12412607.html - Constraint sc = new Constraint(); + ServletConstraint sc = new ServletConstraint(); sc.setName("No trace"); ConstraintMapping cm = new ConstraintMapping(); cm.setMethod("TRACE"); @@ -1065,8 +1064,6 @@ public class RouterConsoleRunner implements RouterApp { cm.setPathSpec("/"); constraints.add(cm); - sc = new Constraint(); - sc.setName("No options"); cm = new ConstraintMapping(); cm.setMethod("OPTIONS"); cm.setConstraint(sc); @@ -1109,11 +1106,11 @@ public class RouterConsoleRunner implements RouterApp { } @Override - public UserIdentity login(String username, Object credentials, ServletRequest request) { - UserIdentity rv = super.login(username, credentials, request); + public UserIdentity login(String username, Object credentials, Request request, Function getOrCreateSession) { + UserIdentity rv = super.login(username, credentials, request, getOrCreateSession); if (rv == null) //_log.logAlways(net.i2p.util.Log.WARN, "Console authentication failed, webapp: " + _webapp + ", user: " + username); - _log.logAlways(net.i2p.util.Log.WARN, "Console authentication failed, user: " + username + " IP: " + request.getRemoteAddr()); + _log.logAlways(net.i2p.util.Log.WARN, "Console authentication failed, user: " + username + " IP: " + Request.getRemoteAddr(request)); return rv; } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java b/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java index f61ab242c..c11d6a581 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java @@ -17,9 +17,9 @@ import net.i2p.I2PAppContext; import net.i2p.util.FileSuffixFilter; import org.apache.tomcat.SimpleInstanceManager; -import org.eclipse.jetty.webapp.Configuration; -import org.eclipse.jetty.webapp.WebAppClassLoader; -import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.ee8.webapp.Configuration; +import org.eclipse.jetty.ee8.webapp.WebAppClassLoader; +import org.eclipse.jetty.ee8.webapp.WebAppContext; /** @@ -223,4 +223,14 @@ public class WebAppConfiguration implements Configuration { /** @since Jetty 7 */ public void postConfigure(WebAppContext context) {} + + /** + * @since Jetty 12 + */ + public boolean abort(WebAppContext context) { return false; } + + /** + * @since Jetty 12 + */ + public boolean isEnabledByDefault() { return true; } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java index 37b12e577..c365e1b80 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/WebAppStarter.java @@ -17,11 +17,12 @@ import net.i2p.util.FileUtil; import net.i2p.util.PortMapper; import net.i2p.util.SecureDirectory; +import org.eclipse.jetty.ee.WebAppClassLoading; +import org.eclipse.jetty.ee8.webapp.WebAppContext; 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; /** @@ -57,7 +58,7 @@ public class WebAppStarter { // javax-annotations-api.jar private static final String CLASS_ANNOT4 = "javax.annotation.security.RunAs"; - private static final String CLASS_CONFIG = "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"; + private static final String CLASS_CONFIG = "org.eclipse.jetty.ee8.webapp.JettyWebXmlConfiguration"; private static final boolean HAS_ANNOTATION_CLASSES; private static final Set BUILTINS = new HashSet(8); @@ -202,12 +203,15 @@ public class WebAppStarter { // Without the default configuration, the web.xml isn't read, and the webapp // won't respond to any requests, even though it appears to be running. // See WebAppContext.loadConfigurations() in source - if (classNames.length == 0) - classNames = wac.getDefaultConfigurationClasses(); + if (classNames.length == 0) { + //classNames = wac.getDefaultConfigurationClasses(); + // These are the defaults as documented in WebAppContext + classNames = new String[] { "org.eclipse.jetty.ee8.webapp.WebXMLConfiguration", "org.eclipse.jetty.ee8.webapp.JettyWebXMLConfiguration" }; + } List newClassNames = new ArrayList(Arrays.asList(classNames)); for (String name : newClassNames) { // fix for Jetty 9.4 ticket #2385 - wac.prependServerClass("-" + name); + WebAppClassLoading.addHiddenClasses(wac, name); } // https://www.eclipse.org/jetty/documentation/current/using-annotations.html // https://www.eclipse.org/jetty/documentation/9.4.x/using-annotations-embedded.html @@ -327,14 +331,14 @@ public class WebAppStarter { * @since 0.9.41 */ private static ContextHandler getWebApp(ContextHandlerCollection server, String appName) { - Handler handlers[] = server.getHandlers(); - if (handlers == null) + List handlers = server.getHandlers(); + if (handlers == null || handlers.isEmpty()) return null; String path = '/'+ appName; - for (int i = 0; i < handlers.length; i++) { - if (!(handlers[i] instanceof ContextHandler)) + for (Handler h : handlers) { + if (!(h instanceof ContextHandler)) continue; - ContextHandler ch = (ContextHandler) handlers[i]; + ContextHandler ch = (ContextHandler) h; if (path.equals(ch.getContextPath())) return ch; } @@ -360,9 +364,7 @@ public class WebAppStarter { * @since 0.9.41 */ private static ContextHandlerCollection getConsoleServer(Server s) { - Handler h = s.getChildHandlerByClass(ContextHandlerCollection.class); - if (h == null) - return null; - return (ContextHandlerCollection) h; + ContextHandlerCollection h = s.getDescendant(ContextHandlerCollection.class); + return h; } } diff --git a/apps/susimail/src/WEB-INF/web.xml b/apps/susimail/src/WEB-INF/web.xml index f02a919d6..5adc3d181 100644 --- a/apps/susimail/src/WEB-INF/web.xml +++ b/apps/susimail/src/WEB-INF/web.xml @@ -82,7 +82,7 @@ - in the base context which invalidates it in our context too. --> - org.eclipse.jetty.servlet.SessionCookie + org.eclipse.jetty.session.SessionCookie SUSIMAILJSESSIONID diff --git a/build.properties b/build.properties index 936891a0e..3c095fcf4 100644 --- a/build.properties +++ b/build.properties @@ -44,8 +44,8 @@ sloccount.report.file=sloccount.sc require.gettext=true # Compile for this version of Java -#javac.version=1.8 -#javac.release=8 +#javac.version=17 +#javac.release=17 # Additional classpath if required #javac.classpath=/PATH/TO/pack200.jar diff --git a/build.xml b/build.xml index 912001e4f..c38679932 100644 --- a/build.xml +++ b/build.xml @@ -14,7 +14,7 @@ and checksum in apps/jetty/build.xml and versions in gradle.properties and apps/jetty/build.gradle --> - + @@ -450,6 +450,9 @@ + + + @@ -874,7 +877,7 @@ - + - - + +
Parses java versions to extract a consistent set of version parts
Returns the Java Platform version, such as {@code 8} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.
Returns the major number version, such as {@code 1} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.
Returns the minor number version, such as {@code 8} for JDK 1.8.0_92 and {@code 2} for JDK 9.2.4.
Returns the micro number version (aka security number), such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4.
Returns the update number version, such as {@code 92} for JDK 1.8.0_92 and {@code 0} for JDK 9.2.4.
Returns the remaining string after the version numbers, such as {@code -internal} for - * JDK 1.8.0_92-internal and {@code -ea} for JDK 9-ea, or {@code +13} for JDK 9.2.4+13.