-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArrayTenaryTrie bug. Infinite Loop with many Handlers #5291
Comments
It fails at 32_763, so fells like a power of 2 thing going on.... |
Maybe some wraparound. Could try replacing the math with Haven't tried this though, don't have the project checked out. |
scratch the |
Some discoveries on
|
OK I can see what is going on..... but before I get into the details I'll just say.... > 50k context handlers ... whaaaaaaaaaaaaat!?!?!?! So the problem is that So first bug is that the class needs to check it's bounds and if we get too many rows it needs to throw... or probably it should have already thrown in the constructor if the capacity is too much. Then how do we support the demand for larger numbers? I can see several solutions:
Note that ArrayTrie itself goes to a much bigger size, but I think it may also have issues with not checking it's bounds. So we need to make sure that it does. For ContextHandlerCollection, it can either:
2 is a quick fix for the OP, but we need to evaluate the space/time tradeoffs with all our Tries. |
@lorban I think this is a good one for you post your current rabbit hole! |
Check capacity of ArrayTernaryTrie Switch to ArrayTrie if over capacity
😃 |
You might want to look into the https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/http/pathmap/PathMappings.html |
I've created PR #5293 with a quick fix. It lacks test harnesses and leaks impl details to the usage of the Trie. I think we still need to review all our Trie implementations for bounds checks and check that size/speed tradeoffs are still relevant. I also think that perhaps we should stop allowing specific Tries to be constructed.... instead have a static factory mechanism that can take the requirements: case insensitive, capacity, growing, expected characters etc. and then we can pick an impl for them. This will alllow us to be smarter in future about swapping out Trie impls. |
Possibly related: #1353 ?
For better or for worse, for the time being, I'll probably have to re-implement the path lookup with a catch-all handler on our side, that seems a lower maintenance burden, so take your time to do it right. |
Here's a template for you to start with ... package org.eclipse.jetty.server.handlers;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.pathmap.MappedResource;
import org.eclipse.jetty.http.pathmap.PathMappings;
import org.eclipse.jetty.http.pathmap.PathSpec;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.component.LifeCycle;
public class PathMappingHandler extends AbstractHandler
{
public static final String ATTR_PATH_SPEC = PathMappingHandler.class.getName() + ".pathSpec";
private final PathMappings<Handler> mappings = new PathMappings<>();
public void addMapping(PathSpec pathSpec, Handler handler)
{
mappings.put(pathSpec, handler);
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
List<MappedResource<Handler>> matches = mappings.getMatches(target);
if (matches != null)
{
for (MappedResource<Handler> mappedResource : matches)
{
PathSpec pathSpec = mappedResource.getPathSpec();
request.setAttribute(ATTR_PATH_SPEC, pathSpec);
Handler handler = mappedResource.getResource();
handler.handle(target, baseRequest, request, response);
if (baseRequest.isHandled())
return;
}
}
response.setStatus(404);
baseRequest.setHandled(true);
}
@Override
protected void doStart() throws Exception
{
for (MappedResource<Handler> handler : mappings.getMappings())
{
if (handler instanceof LifeCycle)
{
LifeCycle lifeCycle = (LifeCycle)handler;
if (!lifeCycle.isStarted())
{
lifeCycle.start();
}
}
}
super.doStart();
}
} You use it like this ... package org.eclipse.jetty.server.handlers;
import org.eclipse.jetty.http.pathmap.RegexPathSpec;
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
public class PathMappingHandlerTest
{
public static void main(String[] args) throws Exception
{
Server server = new Server(9090);
PathMappingHandler pathMappingHandler = new PathMappingHandler();
server.setHandler(pathMappingHandler);
pathMappingHandler.addMapping(new ServletPathSpec("/hello"), new HelloHandler("greetings"));
pathMappingHandler.addMapping(new RegexPathSpec("/hello/.*/earthling"), new HelloHandler("earthling"));
// final "default" path-spec that will be used if nothing above matches
pathMappingHandler.addMapping(new ServletPathSpec("/"), new DefaultHandler());
server.start();
server.join();
}
} Example results. [joakim@hyperion junk][master*]$ curl http://localhost:9090/hello
greetings
[joakim@hyperion junk][master*]$ curl http://localhost:9090/hello/fellow/earthling
earthling
[joakim@hyperion junk][master*]$ curl http://localhost:9090/something/not/found
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 404 Not Found</title>
</head>
<body><h2>HTTP ERROR 404 Not Found</h2>
<table>
<tr><th>URI:</th><td>/something/not/found</td></tr>
<tr><th>STATUS:</th><td>404</td></tr>
<tr><th>MESSAGE:</th><td>Not Found</td></tr>
<tr><th>SERVLET:</th><td>-</td></tr>
</table>
<hr><a href="http://eclipse.org/jetty">Powered by Jetty:// 9.4.30.v20200611</a><hr/>
</body>
</html> |
This issue has been automatically marked as stale because it has been a |
This issue has been closed due to it having no activity. |
@lorban is this actually fixed or needs to be reopened? |
fails with
The trie only contains ~15k entries of the 60k that were all acknowledged with a true return on .put().
This fails no matter what capacity is given to the Trie.
This leads to an infinite loop in org.eclipse.jetty.server.handler.ContextHandlerCollection.newHandlers with a lot (>50k im my case) of handlers.
The text was updated successfully, but these errors were encountered: