Skip to content
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

Expression Language issue #12664

Open
javad-salehi opened this issue Dec 28, 2024 · 7 comments
Open

Expression Language issue #12664

javad-salehi opened this issue Dec 28, 2024 · 7 comments

Comments

@javad-salehi
Copy link

Hello, first of all, I would like to thank you for all your efforts.
In a JSP page, using ${something} when something is not set or does not exist causes the RPS on my system (which can handle up to 10,000 RPS) to drop to less than 2,000. However, if a value is actually set for it, there is no issue. Another scenario is that if no value is set, but the scope is explicitly specified (e.g., ${requestScope.something}), there is no problem.
version : 12.0.* + all jetty dependency ( jetty-ee10-*).
It doesn't make a difference whether with session or without session, with virtual threads or platform threads — I even tested it with Tomcat Jasper, and it was still the same.
And unfortunately, I don't know anything else I can do to figure out where the problem is coming from.

@javad-salehi javad-salehi added the Bug For general bugs on Jetty side label Dec 28, 2024
@janbartel
Copy link
Contributor

janbartel commented Dec 28, 2024 via email

@javad-salehi
Copy link
Author

javad-salehi commented Dec 28, 2024

I tested it with Tomcat and Jasper, and I didn't encounter this issue.
I played around with VisualVM a bit and realized that almost all the threads are stuck in the 'Monitoring' state when I use ${something}. I'm not sure exactly what this means.

@janbartel
Copy link
Contributor

@javad-salehi have you tried pre-compiling your jsp page, if so, did it make a difference? Have you modified the default settings of the jsp servlet at all? Can you post a thread dump showing the problem? I'm doubtful it is Jetty, because the interpretation of all jsp pages is purely done by Jasper.

@javad-salehi
Copy link
Author

My entire code is very simple, and all the settings are default.
jetty :
Server server = new Server(80);
WebAppContext webCtx = new WebAppContext("webapp/myapp","");
server.setHandler(webCtx);
server.start();
server.join();

web.xml & jsp config :

jsp
org.apache.jasper.servlet.JspServlet
3

development
false


fork
false


mappedfile
false



jsp
*.jsp

jsp page :
<%@page session="false" pageEncoding="utf-8" %>

hello , ${something}
hello , ${pageScope.something} <!-- This works well. -->
dependency : 12.0.16 or older org.eclipse.jetty jetty-server ${jetty-ver} org.eclipse.jetty.ee10 jetty-ee10-webapp ${jetty-ver} org.eclipse.jetty.ee10 jetty-ee10-servlet ${jetty-ver} org.eclipse.jetty.ee10 jetty-ee10-annotations ${jetty-ver} org.eclipse.jetty.ee10 jetty-ee10-apache-jsp ${jetty-ver} ![Untitled](https://github.com/user-attachments/assets/921e36b4-b56d-43e1-b5ae-bc882b3e34c3) [dump.txt](https://github.com/user-attachments/files/18286992/dump.txt)

@janbartel
Copy link
Contributor

@javad-salehi your stacktrace shows that almost all of your available jetty threads are trying to load a class asked for by Jasper:

        at org.eclipse.jetty.ee10.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:424)
        - waiting to lock <0x000000070b6f25f8> (a java.lang.Object)
        at java.lang.ClassLoader.loadClass([email protected]/ClassLoader.java:528)
        at java.lang.Class.forName0([email protected]/Native Method)
        at java.lang.Class.forName([email protected]/Class.java:578)
        at java.lang.Class.forName([email protected]/Class.java:557)
        at jakarta.el.ImportHandler.getClassFor(ImportHandler.java:155)
        at jakarta.el.ImportHandler.resolveClassFor(ImportHandler.java:143)
        at jakarta.el.ImportHandler.resolveClass(ImportHandler.java:107)
        at jakarta.servlet.jsp.el.ImportELResolver.getValue(ImportELResolver.java:64)
        at org.apache.jasper.el.JasperELResolver.getValue(JasperELResolver.java:130)
        at org.apache.el.parser.AstIdentifier.getValue(AstIdentifier.java:94)
        at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:152)
        at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:701)
        at org.apache.jsp.jsp.pageC_jsp._jspService(pageC_jsp.java:120)

I'm pretty sure that if you put that in the debugger the classname it's looking for is something. If you look at the stacktrace, the ImportELResolver is trying to work out whether the reference in the ${} is a class, a static field etc etc. It so happens that the jetty WebAppC lassLoader synchronizes on the ClassLoader.getClassLoadingLock(classname) when trying to load the class. Maybe Tomcat/Jasper doesn't. Anyway, as you don't have a class called something, then loading the class never succeeds, so every thread will try to load it and fail. The javadoc for ClassLoader.getClassLoadingLock does say that in some cases the lock will be the ClassLoader itself which could lead to the contention you're seeing.

Best way to avoid it is to ensure your ${} references are correct.

@javad-salehi
Copy link
Author

Honestly, I'm not exactly sure what I should do, I just know that according to the standard, if we have something like ${something}, JSP(jasper) should first check in the page scope, request scope, session scope, and app scope to find it. And for default setting, if there is no value, it should easily be set to null.
If there’s an issue with ${something}, then why doesn’t it cause a problem if I explicitly specify the scope? For example, if it’s explicitly written as ${pageScope.something} or ${requestScope.something}.
Anyway, I really appreciate your responses and guidance. I’ll try to understand exactly what the problem is, but Please run this project and send several thousand requests using Apache Benchmark or any other tool :

sample-jetty.zip

@janbartel
Copy link
Contributor

If you have ${pageScope.something} that definitively says look only in the pageScope for a matching variable name, so fast to fail as you don't have such a variable. If you have ${something} it may well try those other implicit objects first (pageScope, requestScope etc) but as nothing is found that matches, it eventually falls through to trying to load a class of that name to satisfy the expression, hitting the class loading lock. Classloading is expensive - in a webapp we have to check first the webapp classloader, and then the parent hierarchy if it is not found. In your case as you don't have a class called something we will have had to travel all the way up the classloader hierarchy, looking in vain for a non-existent class. So when your system is under load, your threads are all going to be hammering on the lock for the non-existent class something and traversing the class hierarchy.

@janbartel janbartel added Not a bug and removed Bug For general bugs on Jetty side labels Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants