codeconsole opened a new pull request, #16797:
URL: https://github.com/apache/grails-core/pull/16797
## Description
`GrailsWebRequestTaskDecorator` (#16230) binds each task started during a
request to a `GrailsWebRequest` of its own, through
`WebUtils.storeGrailsWebRequest`. That also stores the task's web request in
the `org.grails.WEB_REQUEST` attribute of the request, which the request thread
is still processing. Once any task has run, `GrailsWebRequest.lookup(request)`
on the request thread returns the task's web request instead of the request
thread's own.
The request thread calls `lookup(request)` in several places, so state lands
on the task's web request instead of the request's:
- `UrlMappingsInfoHandlerAdapter` sets the action name and controller
namespace, and hands the web request to the action result transformers.
- `GrailsDispatcherServlet.checkMultipart` calls
`multipartRequestResolved()` (#16149). That rebuilds the task's `params`
instead of those the request thread read before the multipart request was
resolved, so the request thread's `params` miss the uploads (the gh-13837 case).
- `DefaultDataBindingSourceCreator`, `GrailsExceptionResolver` and
`ResponseRedirector` look it up the same way.
For example, an interceptor whose `before()` starts a `task { }` that
finishes before the action runs leaves the action name on the task's web
request.
### Changes
- **The task's web request is bound to the task's thread only.** The
decorator sets it in `RequestContextHolder` and no longer stores it on the
request, so the attribute keeps the request thread's web request.
- **`GrailsWebRequest.lookup(HttpServletRequest)` returns the thread's own
web request for its own request.** When the web request bound to the calling
thread was built with that very request object, it is returned. Otherwise the
attribute is read as before, falling back to the thread's web request. So a
task still finds its own web request from the request it was given, as it did
when the attribute held it, and the request thread finds its own, including
through a wrapper such as the dispatcher's multipart request. The common case,
a lookup with the request the web request was built with, now skips the
attribute read.
### Tests
- `GrailsWebRequestTaskDecoratorSpec`: after a task of the request has run
on another thread, the request attribute, `lookup(request)`, `lookup` through a
wrapper and `lookup()` all return the request thread's web request, and
`multipartRequestResolved()` through the dispatcher's wrapper rebuilds the
request thread's `params`. Both fail on 8.0.x. A task still finds its own web
request from its request.
- `GrailsWebRequestSpec`: `lookup(request)` returns the thread's web request
for its own request and the stored one for a wrapper (fails on 8.0.x), the
stored one for another request, such as a forward's, and the thread's web
request, or null, when the request holds none.
### Not covered
`AsyncWebRequestPromiseDecorator` (`WebPromises`) still stores its task's
web request on the request. Its tasks run once the action has started
asynchronous processing, and with this change each one finds its own web
request from the request it renders through.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]