-
Notifications
You must be signed in to change notification settings - Fork 38.3k
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
New OncePerRequestFilter behavior breaks RequestContextFilter on Jetty after sendError #23196
Comments
@rstoyanchev, this appears to be a possible regression introduced in conjunction with #22989. Can you take a look at it? |
@svschouw-bb, thanks for reporting this and apologies for the disruption.
The filter was created long before the Servlet API had a formal concept of different dispatcher types. Nowadays it's more like once per top-level REQUEST, ASYNC, or ERROR dispatch. Jetty however shreds the assumption those are top-level. Taking a step back we can say once per top-level dispatch, i.e. filter only the first invocation of @rwinch can you explain why it was important in your case for #22989 to be invoked on an ERROR dispatch that's already nested within a REQUEST dispatch? Presumably any initialization done by the filter has already been done for the current thread. We could either roll back this change, or at best turn it into an opt-in mechanism with something like |
As far as I can tell it was to mirror the change in spring-projects/spring-session#1308. The problem there was that they use a |
Okay but I still don't understand why the request isn't wrapped? The behavior in Jetty is that the error dispatch is performed within the current stack. That means we are still within the try-finally of |
From section 10.9.3 of the Servlet 3.1 book:
So Jetty properly dispatches the request on the original request and response objects, causing the wrapping to be undone. There is nothing (as far as I can see, I didn't check thoroughly) which says the attributes should be cleared, and Jetty doesn't clear hem. I guess a problem is that Jetty only applies the "unwrapped" portion of the specification, and not the "unfiltered" portion. So it could be considered a Jetty bug. |
@rstoyanchev As mentioned in the previous comment, the issue is that error is a new dispatch and the request is no longer wrapped. This means that the request is not wrapped again on error dispatch. Here are some additional details spring-projects/spring-session#1308 (comment) |
Thanks for the pointer, @svschouw-bb. Indeed the error dispatch needs to be performed with the original request and response which explains why they are unwrapped. So for a nested ERROR dispatch:
The Spring Framework has three filters that fall under 1) (OSIV, OEIV, and RequestContext) and one that falls under 2) (forwarded headers), and the rest don't process ERROR dispatches. There is nothing in the Spring Framework for 3), but My suggestion is to add I see this as the best compromise in the given situation and the most we can do. Does it seem acceptable? |
Not sure if it was implied, but for (1) it would say they need to ignore nested error calls (i.e.: just the regular Other than that it sounds good to me. (Also, as for the |
I see no reason for Essentially unless you opt into processing a nested ERROR dispatch, you will not be called a second time as long as long as you're still within a previous Filter invocation on the call stack. As for the case of sendError before a Filter is reached, that should work fine since the "alreadyFiltered" attribute would not have been set yet. |
I'm concerned with how complex the For example have a RequestWrapperFilter which works for wrapping the request once. Perhaps it even uses something like |
I'll experiment with a base class to help ensure the request (and/or response) remain wrapped. Maybe that would solve the original problem in a different way, and there is no need to re-invoke |
Here is what I've come up with. There is a new protected method in I did consider creating some sort of RequestWrappingFilter but didn't find a good solution there. Separate methods to wrap the request and/or response aren't ideal, since if you want to do both, it's best to do them in one method, and such a method cannot return both wrapped. I've also updated the |
Curious if the request is then wrapped twice in Tomcat for error dispatch since the attributes are cleared out? |
It shouldn't be wrapped twice. In Tomcat or whenever the ERROR dispatch is not nested, the filter chain is exited all the way. |
The new @rwinch this means there is a need for a follow-up for spring-projects/spring-session#1308 to ensure affected filters implement the new method. By the way I checked Tomcat and Jetty behavior in case of an error, regarding double wrapping:
|
After the change to
OncePerRequestFilter
in #22989, when using aRequestContextFilter
, the request context will no longer be available aftersendError(...)
completes in Jetty. This means that the usage of any@Scope("request")
beans in places like the afterCompletion in interceptors or on the return path of filters will not work, nor will more general usage ofRequestContextHolder.getRequestAttributes()
work.The problem is that the change in
OncePerRequestFilter
causes the filter to be processed again, even though it is a OncePerRequestFilter. And theRequestContextFilter
is not designed to be nested. Thefinally
block clears all request attributes, even when attributes were set before the filter started.I'm not really sure what the best solution would be. Maybe introduce a
OncePerRequestFilter.shouldNotFilterOnNestedErrorDispatch()
or something. Or maybe makeRequestContextFilter
restore the previous request context, instead of clearing everything (it seems likeFrameworkServlet
does this too)? Or both.Affected version: 5.1.8
The text was updated successfully, but these errors were encountered: