mirror of
https://github.com/yacy/yacy_search_server.git
synced 2026-10-25 05:54:15 +00:00
transform Handler into Servlet-Filter
to further remove dependencies from jetty
This commit is contained in:
1 parent
b32b659023
commit
dd0d4ee962
6 files changed
+150
-84
No files matched your search
@@ -15,6 +15,16 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
|
||||
import net.yacy.cora.util.ConcurrentLog;
|
||||
|
||||
/**
|
||||
* Last-resort exception barrier wrapped around the complete handler chain.
|
||||
*
|
||||
* Note for servlet container migration: this must stay a container level
|
||||
* handler (it can not become a servlet filter): inside the servlet context a
|
||||
* filter would catch servlet exceptions before the containers error dispatch
|
||||
* and thereby replace the YaCyErrorHandler error page with a plain text stack
|
||||
* trace. Its purpose is to catch failures outside the servlet context, e.g.
|
||||
* in the transparent proxy handlers.
|
||||
*/
|
||||
public class CrashProtectionHandler extends HandlerWrapper implements Handler, HandlerContainer {
|
||||
|
||||
public CrashProtectionHandler() {
|
||||
|
||||
@@ -38,6 +38,9 @@ import org.eclipse.jetty.util.component.DumpableCollection;
|
||||
* previously available in the deprecated IPAccessHandler.
|
||||
* </p>
|
||||
*
|
||||
* Note for servlet container migration: the InetAccessHandler of Jetty 10 and
|
||||
* later supports path patterns natively ("addr|path" syntax), this class can
|
||||
* then be removed.
|
||||
*/
|
||||
public class InetPathAccessHandler extends InetAccessHandler {
|
||||
|
||||
|
||||
@@ -24,14 +24,18 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.KeyStore;
|
||||
import java.util.EnumSet;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
@@ -46,13 +50,16 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.server.handler.InetAccessHandler;
|
||||
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
import net.yacy.cora.protocol.ConnectionInfo;
|
||||
import net.yacy.cora.util.ConcurrentLog;
|
||||
import net.yacy.http.servlets.MonitorFilter;
|
||||
import net.yacy.http.servlets.YaCyDefaultServlet;
|
||||
import net.yacy.search.Switchboard;
|
||||
import net.yacy.search.SwitchboardConstants;
|
||||
@@ -74,6 +81,21 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
|
||||
|
||||
this.server = new Server();
|
||||
|
||||
// remove the ConnectionInfo tracking entry (added per request by the MonitorFilter)
|
||||
// when the tcp connection closes; added as bean to each connector below
|
||||
final Connection.Listener connectionCloseMonitor = new Connection.Listener() {
|
||||
@Override
|
||||
public void onOpened(final Connection connection) {
|
||||
}
|
||||
@Override
|
||||
public void onClosed(final Connection connection) {
|
||||
final InetSocketAddress remote = connection.getEndPoint().getRemoteAddress();
|
||||
if (remote != null) {
|
||||
ConnectionInfo.removeServerConnection(MonitorFilter.connectionId(remote.getAddress().getHostAddress(), remote.getPort()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final int cores = Runtime.getRuntime().availableProcessors();
|
||||
final int acceptors = Math.max(1, Math.min(4, cores/2)); // original: Math.max(1, Math.min(4,cores/8));
|
||||
|
||||
@@ -86,7 +108,7 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
|
||||
connector.setName("httpd-" + host + ":" + Integer.toString(port));
|
||||
connector.setIdleTimeout(9000); // timout in ms when no bytes send / received
|
||||
connector.setAcceptQueueSize(128);
|
||||
|
||||
connector.addBean(connectionCloseMonitor);
|
||||
|
||||
this.server.addConnector(connector);
|
||||
|
||||
@@ -113,6 +135,7 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
|
||||
sslConnector.setPort(sslport);
|
||||
sslConnector.setName("ssld:" + Integer.toString(sslport)); // name must start with ssl (for withSSL() to work correctly)
|
||||
sslConnector.setIdleTimeout(9000); // timout in ms when no bytes send / received
|
||||
sslConnector.addBean(connectionCloseMonitor);
|
||||
|
||||
this.server.addConnector(sslConnector);
|
||||
ConcurrentLog.info("SERVER", "SSL support initialized successfully on port " + sslport);
|
||||
@@ -156,6 +179,12 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
|
||||
//sholder.setInitParameter("welcomeFile", "index.html"); // default is index.html, welcome.html
|
||||
htrootContext.addServlet(sholder, "/*");
|
||||
|
||||
// as fundamental component this filter is hardcoded too: it feeds the
|
||||
// Connections_p.html monitoring and rejects requests above the connection limit
|
||||
final FilterHolder monitorFilter = new FilterHolder(MonitorFilter.class);
|
||||
monitorFilter.setAsyncSupported(true);
|
||||
htrootContext.addFilter(monitorFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
final GzipHandler gzipHandler = new GzipHandler();
|
||||
/*
|
||||
* Decompression of incoming requests body is required for index distribution
|
||||
@@ -198,9 +227,9 @@ public class Jetty9HttpServerImpl implements YaCyHttpServer {
|
||||
if (sb.getConfigBool(SwitchboardConstants.PROXY_TRANSPARENT_PROXY, false)) {
|
||||
// Proxyhandlers are only needed if feature activated (save resources if not used)
|
||||
ConcurrentLog.info("SERVER", "load Jetty handler for transparent proxy");
|
||||
handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler, new ProxyCacheHandler(), new ProxyHandler()});
|
||||
handlers.setHandlers(new Handler[]{domainHandler, new ProxyCacheHandler(), new ProxyHandler()});
|
||||
} else {
|
||||
handlers.setHandlers(new Handler[]{new MonitorHandler(), domainHandler});
|
||||
handlers.setHandlers(new Handler[]{domainHandler});
|
||||
}
|
||||
// context handler for dispatcher and security (hint: dispatcher requires a context)
|
||||
final ContextHandler context = new ContextHandler();
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/**
|
||||
* MonitorHandler
|
||||
* Copyright 2014 by Sebastian Gaebel
|
||||
* First released 15.05.2014 at https://yacy.net
|
||||
*
|
||||
* $LastChangedDate$
|
||||
* $LastChangedRevision$
|
||||
* $LastChangedBy$
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program in the file lgpl21.txt
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.yacy.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.yacy.cora.protocol.ConnectionInfo;
|
||||
import net.yacy.cora.protocol.Domains;
|
||||
import net.yacy.cora.protocol.RequestHeader;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
public class MonitorHandler extends AbstractHandler {
|
||||
|
||||
private final Connection.Listener remover = new Connection.Listener() {
|
||||
|
||||
@Override
|
||||
public void onClosed(Connection c) {
|
||||
ConnectionInfo.removeServerConnection(c.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpened(Connection c) {
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request,
|
||||
HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
final Connection connection = baseRequest.getHttpChannel().getEndPoint().getConnection();
|
||||
final ConnectionInfo info = new ConnectionInfo(
|
||||
baseRequest.getScheme(),
|
||||
RequestHeader.client(baseRequest) + ":" + baseRequest.getRemotePort(),
|
||||
baseRequest.getMethod() + " " + baseRequest.getHttpURI().getPathQuery(),
|
||||
connection.hashCode(),
|
||||
baseRequest.getTimeStamp(),
|
||||
-1);
|
||||
|
||||
if (ConnectionInfo.getServerConnections().contains(info)) {
|
||||
ConnectionInfo.removeServerConnection(info);
|
||||
} else {
|
||||
connection.addListener(remover);
|
||||
}
|
||||
ConnectionInfo.addServerConnection(info);
|
||||
|
||||
if (ConnectionInfo.isServerCountReached()) {
|
||||
if (Domains.isLocal(baseRequest.getRemoteAddr(), baseRequest.getRemoteInetSocketAddress().getAddress())) return;
|
||||
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,"max. server connections reached (increase /PerformanceQueues_p.html -> httpd Session Pool).");
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,12 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
/**
|
||||
* handling of request to virtual ".yacy" domain determines public adress from
|
||||
* seedlist and forwards modified/wrapped request to it
|
||||
*
|
||||
* Note for servlet container migration: this must stay a container level
|
||||
* handler (it can not become a servlet filter), because it cooperates with the
|
||||
* ProxyHandler chain: the re-dispatched request with the rewritten (remote)
|
||||
* host is picked up and forwarded to the peer by the transparent proxy
|
||||
* handlers, before the local servlet context would handle it.
|
||||
*/
|
||||
public class YacyDomainHandler extends AbstractHandler implements Handler {
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* MonitorFilter
|
||||
* Copyright 2014 by Sebastian Gaebel
|
||||
* First released 15.05.2014 at https://yacy.net
|
||||
*
|
||||
* $LastChangedDate$
|
||||
* $LastChangedRevision$
|
||||
* $LastChangedBy$
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program in the file lgpl21.txt
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.yacy.http.servlets;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.yacy.cora.protocol.ConnectionInfo;
|
||||
import net.yacy.cora.protocol.Domains;
|
||||
import net.yacy.cora.protocol.RequestHeader;
|
||||
|
||||
/**
|
||||
* Records incoming server requests into {@link ConnectionInfo} (displayed on
|
||||
* Connections_p.html) and rejects remote requests with http status 503 when
|
||||
* the configured maximum number of server connections is reached.
|
||||
*
|
||||
* This is a plain servlet filter (former Jetty handler MonitorHandler); the
|
||||
* tracking entry of a connection is removed on connection close by a
|
||||
* servlet-container specific listener, see Jetty9HttpServerImpl.
|
||||
*/
|
||||
public class MonitorFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ConnectionInfo id of the tcp connection identified by client address and port
|
||||
*/
|
||||
public static int connectionId(String remoteAddr, final int remotePort) {
|
||||
// the servlet API reports IPv6 addresses in bracketed form ("[::1]"), the
|
||||
// connection endpoint in plain form: normalize to the plain form
|
||||
if (remoteAddr.startsWith("[") && remoteAddr.endsWith("]")) {
|
||||
remoteAddr = remoteAddr.substring(1, remoteAddr.length() - 1);
|
||||
}
|
||||
return (remoteAddr + ":" + remotePort).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
final HttpServletRequest hrequest = (HttpServletRequest) request;
|
||||
final String query = hrequest.getQueryString();
|
||||
final ConnectionInfo info = new ConnectionInfo(
|
||||
hrequest.getScheme(),
|
||||
RequestHeader.client(hrequest) + ":" + hrequest.getRemotePort(),
|
||||
hrequest.getMethod() + " " + hrequest.getRequestURI() + (query == null ? "" : "?" + query),
|
||||
connectionId(hrequest.getRemoteAddr(), hrequest.getRemotePort()),
|
||||
System.currentTimeMillis(),
|
||||
-1);
|
||||
|
||||
// a keep-alive connection reuses the id: remove a previous entry to show the latest request
|
||||
ConnectionInfo.removeServerConnection(info);
|
||||
ConnectionInfo.addServerConnection(info);
|
||||
|
||||
if (ConnectionInfo.isServerCountReached()
|
||||
&& !Domains.isLocal(hrequest.getRemoteAddr(), null)) {
|
||||
((HttpServletResponse) response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
|
||||
"max. server connections reached (increase /PerformanceQueues_p.html -> httpd Session Pool).");
|
||||
return;
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user