HEAD/GET in MVC not fully backward-compatible [SPR-14383] #18956
Comments
Francisco Lozano commented |
Rossen Stoyanchev commented It sounds exactly like #18753 which was fixed in 4.3 RC2. Are you sure you're not running with an older RC by any chance? I can't reproduce it with 4.3 GA and the above controller:
|
Francisco Lozano commented I'm 100% sure we're running 4.3.0 final, not RC:
I will try to isolate the behaviour, the controller is pretty complex (code pasted above is just a subset). |
Rossen Stoyanchev commented Okay I figured it was pretty unlikely but worth checking. |
Francisco Lozano commented OK, something strange: @RequestMapping(value = "/*", method = HEAD, produces = "application/json") the code goes to the head, as it used to in 4.2. But this doesn't explain why you can't reproduce with the example above... :/ |
Rossen Stoyanchev commented Okay that's the part I was missing. If I add an Accept header I can see the issue:
I presume you have that? So I guess In I'm wondering now if this is right or wrong. Perhaps we need to update |
Francisco Lozano commented yes, our client adds "Accept" header |
Rossen Stoyanchev commented For the "right or wrong" comment what I meant is that maybe it's behaving as it should be (forgetting for a moment the fact it's a regression). After all HEAD is meant to be the same as GET minus the body. However an explicit mapping to HTTP HEAD clearly should take precedence. To explain the current behavior of For HTTP HEAD we need to check the HTTP method first so that an explicit mapping to HEAD always wins over any other mapping. For all other cases, the HTTP method comparison needs to remain as it is now after all other conditions. That means also that an explicit HTTP HEAD mapping would take precedence over more specific URL patterns, which is really generalization of the case here with a produces condition. |
Francisco Lozano commented I understand the fact that HEAD is supposed to be the same as GET. In this case, we took advantage of the different verb to implement a little different behaviour: we allow to check for existence of a resource (with HEAD) but we only allow to retrieve its content to some principals (with GET). That's how we found this situation, because in a test 404 was expected but 401 was returned instead. To me, intuitively HTTP method is "naturally" the first piece to check, but I didn't consider the possibility of having no-HTTP-method mappings... sounds tricky. I will workaround it for now by adding "produces" to our HEAD mappings, which is not incorrect in any way and is not a big effort. Thanks a lot for taking a look at this issue! |
Rossen Stoyanchev commented Come to think of it, Isn't having the produces condition on the HEAD mapping necessary? If the Accept header is not application/json the response for the GET should be a 415 instead and the HEAD should match that. This doesn't change my thinking that we need a fix in RequestMappingInfo so that explicit HEAD mapping has precedence. It's just that as a result it becomes the application responsibility to ensure that the resulting HEAD responses are consistent with GET. |
Francisco Lozano commented I think it's OK to let the developer be responsible of that. Developer is already responsible for that in 4.2, and to me it follows the principle of least surprise. |
Rossen Stoyanchev commented I've pushed a fix and confirmed it with the repro project but would be great if you could confirm also after this build is done. |
Francisco Lozano commented My test passes now with latest 4.3.1 SNAPSHOT, thank you! |
Rossen Stoyanchev commented Thanks for confirming. |
Francisco Lozano opened SPR-14383 and commented
I have a controller that looks more or less like this (just relevant parts):
Now, always GET gets invoked instead of HEAD. We are still debugging but we're thinking that the compareTo method in RequestMethodsRequestCondition is related to the issue.
Affects: 4.3 GA
Referenced from: commits 058279b
1 votes, 3 watchers
The text was updated successfully, but these errors were encountered: