Copilot commented on code in PR #16146:
URL: https://github.com/apache/grails-core/pull/16146#discussion_r3775048523


##########
grails-web-mvc/src/main/groovy/org/grails/web/filters/HiddenHttpMethodFilter.java:
##########
@@ -71,14 +71,22 @@ protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse
     }
 
     protected String getHttpMethodOverride(HttpServletRequest request) {
-        String httpMethod = request.getParameter(methodParam);
+        String httpMethod = null;
+        if (!isMultipart(request)) {
+            httpMethod = request.getParameter(methodParam);
+        }

Review Comment:
   This disables `_method` overrides for every multipart form, so existing 
multipart PUT/PATCH/DELETE forms are now dispatched as POST. The newly 
registered `MultipartFilter` runs at `GrailsFilters.FIRST`, before this filter, 
so multipart parsing has already gone through the configured resolver; restore 
parameter lookup rather than removing this supported behavior.



##########
grails-web-mvc/src/main/groovy/org/grails/web/servlet/mvc/GrailsWebRequestFilter.java:
##########
@@ -58,6 +59,9 @@ protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse
         boolean isIncludeOrForward = WebUtils.isForwardOrInclude(request);
         GrailsWebRequest previous = isIncludeOrForward ? 
GrailsWebRequest.lookup(request) : null;
         GrailsWebRequest webRequest = new GrailsWebRequest(request, response, 
getServletContext());
+        if (request instanceof MultipartHttpServletRequest) {
+            webRequest.setMultipartRequest(request);
+        }

Review Comment:
   Checking only the outer request misses a multipart request hidden by an 
earlier wrapper. `HiddenHttpMethodFilter` runs before this filter and wraps 
requests when the override header is present, so downstream code using the 
bound `GrailsWebRequest` can still see a non-multipart request until the 
dispatcher runs. Resolve the native multipart request here, as the dispatcher 
does.



##########
grails-web-mvc/src/main/groovy/org/grails/web/servlet/mvc/GrailsDispatcherServlet.groovy:
##########
@@ -89,6 +100,7 @@ class GrailsDispatcherServlet extends DispatcherServlet 
implements ServletContex
                 if (webRequest != null) {
                     webRequest.multipartRequest = processedRequest
                 }
+                return processedRequest

Review Comment:
   None of the new dispatcher multipart paths is exercised by the added tests. 
Add coverage for an active `GrailsWebRequest` behind a nested request wrapper 
and for `checkMultipart` returning and storing a newly resolved request, since 
these are the paths that preserve valid uploads through security wrappers.



##########
grails-test-suite-uber/src/test/groovy/org/grails/web/filters/HiddenHttpMethodFilterTests.groovy:
##########
@@ -71,4 +70,23 @@ class HiddenHttpMethodFilterTests {
 
         assertEquals "DELETE", method
     }
+
+    @Test
+    void testMultipartRequestDoesNotParseParameters() {
+        def filter = new HiddenHttpMethodFilter()
+        def req = new MockHttpServletRequest() {
+            @Override
+            String getParameter(String name) {
+                throw new IllegalStateException('Multipart request parameters 
must not be parsed by this filter')
+            }
+        }
+        req.contentType = 'multipart/form-data; boundary=test'
+        req.method = 'POST'
+        def res = new MockHttpServletResponse()
+        String method = null
+
+        filter.doFilter(req, res, { req2, res2 -> method = req2.method } as 
FilterChain)
+
+        assertEquals('POST', method)

Review Comment:
   This assertion codifies the multipart `_method` regression: a multipart form 
containing `_method=DELETE` must still reach the chain as DELETE after the 
earlier multipart resolver has wrapped it. Replace this with a resolved 
multipart request carrying `_method` and retain a regression test that proves 
no container-level parsing occurs before resolution.



##########
grails-controllers/src/main/groovy/org/grails/plugins/web/controllers/ControllersAutoConfiguration.java:
##########
@@ -101,6 +102,20 @@ public CharacterEncodingFilter characterEncodingFilter() {
         return characterEncodingFilter;
     }
 
+    @Bean
+    @ConditionalOnMissingBean(MultipartFilter.class)

Review Comment:
   This condition does not detect the common customization 
`FilterRegistrationBean<MultipartFilter>` because the bean itself is a 
registration wrapper, not a `MultipartFilter`. The auto-configuration can 
therefore register a second multipart filter (or collide on the natural 
`multipartFilter` bean name); include `FilterRegistrationBean` as a 
parameterized container so user registrations back this bean off.
   
   This issue also appears in the following locations of the same file:
   - line 109
   - line 115



-- 
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]

Reply via email to