-
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
java.lang.NullPointerException: Cannot invoke "String.startsWith(String)" because "etag" is null #11925
Comments
The NPE needs to be fixed, but it's caused by bad assumptions in your implementation. Looking at your implementation and it's use of DefaultServlet you are abusing it in various ways. The DefaultServlet on Jetty 6 thru Jetty 12 can handle servlet url-patterns of The only reason you seem to have this setup is an attempt to configure the |
Why are you using a URLResource? |
You have this wrong ..
To obtain a ResourceFactory it should be bound to a component in Jetty that has a LifeCycle (such as a Like this. ResourceFactory resourceFactory = ResourceFactory.of(context); As for the code you have as ... protected static Resource getClientPath(String path) throws URISyntaxException
{
if (path != null)
return prf.newResource(getPath(path));
final var p = getPath("jrt:/jrm.merged.module/webclient/");
if (Files.exists(p))
return prf.newResource(p);
return urf.newResource(FullServer.class.getResource("/webclient/"));
} That should read like ... protected static Resource getClientPath(ResourceFactory resourceFactory, String path) throws IOException
{
Resource resource;
if (path != null)
{
resource = resourceFactory.newResource(path);
if (Resources.exists(resource))
return resource;
resource = resourceFactory.newClassLoaderResource(path, true);
if (Resources.exists(resource))
return resource;
}
resource = resourceFactory.newResource("jrt:/jrm.merged.module/webclient/");
if (Resources.exists(resource))
return resource;
URL url = FullServer.class.getResource("/webclient/");
if (url != null)
{
resource = resourceFactory.newResource(url);
if (Resources.exists(resource))
return resource;
}
throw new FileNotFoundException("Unable to find webclient path");
} This uses only 1 ResourceFactory, the one tied to the LifeCycle of the context. |
Thanks for the indications @joakime maybe related I noticed the warning message when launched :
Here is the full output when launched :
to get the resourceFactory I did like this :
I also tried with ResourceFactory.root(); with no better success I will commit what I modified, if you want to look at what I did (I only modified jrm.server.Server, not the FullServer) |
The path on a Base Resource MUST be the correct path as it is stored on disk. I see several different cases in your output (the
That first directory entry One case is an alias to the other as-stored case. The case differences usually comes from a configuration file somewhere, where the string is being used as-is (without a real-path lookup / resolution / normalization / de-symlinking / etc) with Jetty's newResource(String). You can fix this by always doing Path.toRealPath() before passing the value into Jetty. |
Once PR #11927 is merged, then I have a few things to do for this issue.
|
I managed to get it working by doing this...
That's a bit ugly but it works
then FileSystems.getPath will return
jetty seems to be happier with the later because of jar:file:/// |
I would expect that to return the URL based on your classpath.
You are finding one of the oddities of java's URL class. This isn't the only bug in the Java URL class. Jetty has a utility built-in to correct that syntax btw (and it is also Windows UNC URI/URL aware) URI uri = org.eclipse.jetty.util.URIUtil.correctURI(url.toUri())
Resource resource = resourceFactory.newResource(uri); |
the case was correct for the class path, the "should not be an alias" message is only because of the missing // I did found in between that correctURI utility method So finally the NPE seems to be linked with the use of a separate URLResourceFactory, as soon as I used the more generic ResourceFactory (with a fixed uri), all started to work ok Thank you should I keep the issue open for reference or close it? |
Opened PR #11930 to address the various concerns brought up here. |
Merged PR #11930 to address the NPE in Etags with URLResource, and also make warning "Base Resource should not be an alias" more clear. |
Jetty version(s)
12.0.10
Jetty Environment
ee9
Java version/vendor
(use: java -version)
openjdk version "21.0.2" 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)
OS type/version
Windows 11 and Linux Debian bookworm (12)
Description
22:46:12.082 [main] INFO org.eclipse.jetty.server.Server - jetty-12.0.8; built: 2024-03-29T19:58:19.443Z; git: ffffdcc; jvm 21.0.2+13-LTS
22:46:12.122 [main] INFO o.e.j.s.DefaultSessionIdManager - Session workerName=node0
22:46:12.132 [main] INFO o.e.j.server.handler.ContextHandler - Started oeje9n.ContextHandler$CoreContextHandler@23941fb4{ROOT,/,b=URLResource@12C8CFCA(jar:file:/D:/GIT/JRomManager/build/install/JRomManager-nogui-noarch/lib/jrm-WebClient-3.0.0.jar!/webclient/),a=AVAILABLE,h=oeje9n.ContextHandler$CoreContextHandler$CoreToNestedHandler@5d908d47{STARTED}}
22:46:12.195 [main] INFO o.e.jetty.server.AbstractConnector - Started HTTP@452e19ca{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
22:46:12.215 [main] INFO org.eclipse.jetty.server.Server - Started oejs.Server@3527942a{STARTING}[12.0.8,sto=0] @642ms
Enter 'stop' to halt:
22:46:17.755 [qtp664792509-41] WARN o.e.jetty.ee9.nested.HttpChannel - /smartgwt/sc/modules/ISC_Core.js
java.lang.NullPointerException: Cannot invoke "String.startsWith(String)" because "etag" is null
at org.eclipse.jetty.http.EtagUtils.rewriteWithSuffix(EtagUtils.java:217)
at org.eclipse.jetty.http.content.PreCompressedHttpContent.(PreCompressedHttpContent.java:46)
at org.eclipse.jetty.ee9.nested.ResourceService.doGet(ResourceService.java:316)
at org.eclipse.jetty.ee9.servlet.DefaultServlet.doGet(DefaultServlet.java:506)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:500)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
at org.eclipse.jetty.ee9.servlet.ServletHolder.handle(ServletHolder.java:765)
at org.eclipse.jetty.ee9.servlet.ServletHandler.doHandle(ServletHandler.java:528)
at org.eclipse.jetty.ee9.nested.ScopedHandler.nextHandle(ScopedHandler.java:195)
at org.eclipse.jetty.ee9.nested.SessionHandler.doHandle(SessionHandler.java:476)
at org.eclipse.jetty.ee9.nested.ScopedHandler.nextHandle(ScopedHandler.java:195)
at org.eclipse.jetty.ee9.nested.ContextHandler.doHandle(ContextHandler.java:1034)
at org.eclipse.jetty.ee9.nested.ScopedHandler.nextScope(ScopedHandler.java:164)
at org.eclipse.jetty.ee9.servlet.ServletHandler.doScope(ServletHandler.java:483)
at org.eclipse.jetty.ee9.nested.ScopedHandler.nextScope(ScopedHandler.java:162)
at org.eclipse.jetty.ee9.nested.SessionHandler.doScope(SessionHandler.java:470)
at org.eclipse.jetty.ee9.nested.ScopedHandler.nextScope(ScopedHandler.java:162)
at org.eclipse.jetty.ee9.nested.ContextHandler.doScope(ContextHandler.java:955)
at org.eclipse.jetty.ee9.nested.ScopedHandler.handle(ScopedHandler.java:125)
at org.eclipse.jetty.ee9.nested.ContextHandler.handle(ContextHandler.java:1693)
at org.eclipse.jetty.ee9.nested.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1575)
at org.eclipse.jetty.ee9.nested.HttpChannel.dispatch(HttpChannel.java:737)
at org.eclipse.jetty.ee9.nested.HttpChannel.handle(HttpChannel.java:510)
at org.eclipse.jetty.ee9.nested.ContextHandler$CoreContextHandler$CoreToNestedHandler.handle(ContextHandler.java:2727)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:851)
at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:597)
at org.eclipse.jetty.server.Server.handle(Server.java:179)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:619)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:411)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:478)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:441)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.produce(AdaptiveExecutionStrategy.java:195)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:979)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1209)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1164)
at java.base/java.lang.Thread.run(Thread.java:1583)
How to reproduce?
happens when serving resources with DefaultServlet and it's precompressed gzip content inside a jar archive as URLResource... My understanding is that jetty is currently unable to provide an etag from httpcontent with that use case
The text was updated successfully, but these errors were encountered: