-
Notifications
You must be signed in to change notification settings - Fork 38.1k
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
@RequestMapping without any attributes behaves as "default endpoint" #22543
Comments
@RestController
is kind of converting the bean into the "default endpoint"
Please note that Spring MVC supports mapping from bean names (that begin with a forward slash See the javadoc for Thus, in your use case, when So that explains why you do not get a 404 for requests to Regarding the |
Nope, there is no similarity. I'm literally sending that
More readable extraction from there:
This controller class is the only bean I have in my freshly created spring boot app. |
@anatoliy-balakirev, thanks for the feedback.
Good to know. Based on some quick experimentation, you should experience the same behavior if you simply annotate your controller class with |
Here is a sample project: https://github.com/anatoliy-balakirev/rest-controller-mapping |
Yep, seems to be the case. So looks like it's kind of getting mapped to "*", which seems to be not so good default, as for me. Would be better to get it not mapped at all as in fact there is no mapping provided. |
I agree that this behavior does not appear to be what the default should be in such cases. I have been able to reproduce this in the following test class based purely on core Spring (using this Person class). In summary, a import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.Person;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@WebAppConfiguration
public class MissingExplicitRequestMappingTests {
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void person() throws Exception {
this.mockMvc.perform(get("/whatever").accept(MediaType.APPLICATION_JSON))//
.andDo(print())//
.andExpect(status().isOk())//
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
}
@Configuration
@EnableWebMvc
static class WebConfig {
@Bean
PersonController personController() {
return new PersonController();
}
}
@RestController("/person")
// @RequestMapping("/person")
static class PersonController {
@GetMapping
public Person getPerson() {
return new Person("Joe");
}
}
} @rstoyanchev, I seem to recall that we once discussed this particular scenario. Can you perhaps provide some light on the subject before I dive any deeper into a search for a solution? |
To add more context to this and why it might be security issue in some cases: |
Tentatively slated for 5.1.6 for further investigation. |
I disagree with the analysis here. Adding a If we were to constraint that, we'd break many valid use cases where people are mapping requests based on params or headers, and not providing any constraint about path. If anything, I think this issue shows that it's easy to get confused and annotate |
@bclozel maybe I'm missing something, but can you please, point me to the place in the spec, which is saying that If backward compatibility in this particular case is really needed (even though I find this default behaviour really confusing) - what about at least issuing some warning at startup? So that when needed - people can explicitly define it as |
@anatoliy-balakirev the If this were about security, then we'd force developers to provide a path and we'd make that attribute mandatory. It's never been the case. Adding a WARN log wouldn't really solve the issue in my opinion. In this case you ran into a problem and I totally get the frustration - the thing is when this happens the problem is quite obvious since this will match many unintended requests, like requests for static resources in a typical Spring Boot setup. I think your suggestion to improve the documentation is the right one, can you suggest places (in the javadoc/reference doc) where you think this could be helpful? |
This is somewhat related to #21585 in the sense that in both cases the class-level mapping is expressed in The trouble is that from a Spring MVC perspective the controller appears to have an empty Perhaps what we could consider flagging such cases where there is nothing but an empty |
I fully agree with that. That's actually what I meant when I said I don't think the reported behavior is what the default should be.
What are you proposing with "flagging": logging or throwing an exception? To me it really seems like a user configuration error if the user doesn't supply any pattern at all. So I'm wondering if throwing an exception would be appropriate (perhaps with a |
If we consider that it's not a valid scenario, then I'd vote to throw an exception, just like we do already for duplicate mappings. But then I'd also vote to move that to 5.2. |
True. If we change the behavior, I also agree that we should do this in 5.2. |
Sorry, just got back here. @bclozel when I look at
It's not clear what Regarding this:
For us problem was absolutely not obvious. In our micro service we have a couple of endpoints and only one had this issue (out of curiosity I tried to do the same for the second one and got startup failure). All endpoints, except for actuator ones were secured, so all requests without security token were returning unauthorised. However, requests to actuator endpoints (but using main app's port) were successfully forwarded to our P.S. But as discussed above - I would also prefer it to throw an exception in that case. |
This has been addressed for Spring MVC controllers in c0b52d0. @rstoyanchev, do you foresee any need to do anything similar for WebFlux? |
Absolutely. |
The change here causes Spring Data REST controllers to break. We have the additional complexity of a global, configurable base URI (e.g. We then have handler methods mapped to both I can of course change our mapping customization to also register a mapping for |
Update: we've decided to log |
The revised implementation has been pushed to |
Sorry to re-open, partly by mistake (hitting the button) but also to discuss a little further. @odrotbohm when is the prefix applied, i.e. what kind of hook is it using? Perhaps we could change where we check for this and still raise an exception? Or alternatively at runtime if we see we're dealing with an empty mapping we have an opportunity still to change how we treat it. |
@odrotbohm, keep in mind also that as of 5.1 there is an option for inserting a common prefix to controller mappings, and if that option is used I would expect the change to work as it was implemented originally. If you're not using that feature perhaps it's something to try and switch to? |
…athPatterns This commit revises the signature of getMappingPathPatterns() in AbstractHandlerMethodMapping to return a set of PathPatterns instead of a set of Strings. See gh-22543
@odrotbohm, since we're planning on releasing 5.2 M1 on Tuesday, it would be great if you could provide feedback to Rossen's questions by midday tomorrow (Monday). Thanks in advance! |
I‘m on PTO next week so I am not sure I’ll be able to investigate. As indicated in Slack Spring Data REST is back to work after you changes. Any chance we postpone any further discussion to after the release? |
OK. Thanks for the heads up.
That's because we switched to logging a warning instead of throwing an exception; however, we are considering changing back to throwing an exception. Hence Rossen's line of questions.
The Spring Framework team will make that decision during tomorrow's team call. |
This commit moves the WebFlux getMappingPathPatterns() implementation from RequestMappingHandlerMapping to RequestMappingInfoHandlerMapping so that subclasses of the latter no longer need to re-implement the method. See gh-22543
After further review, currently a single (i.e. method-level) |
This is likely to break some existing tests that rely on the current behavior. Our own tests had several but it also helped to reveal bad tests in |
Hi. Sorry, I'm a bit lost here. So how is it solved eventually? By logging warning of throwing an exception? |
Neither warning, nor exception. Rather the same as "" (empty path). |
Spring version: 5.1.5.RELEASE
In one of our micro services we've made a mistake and instead of writing something like this:
Created this:
Everything worked fine, all our requests were handled but then at some point we realised that all requests, even for non-existing endpoints, are mapped to that controller. So this:
http://localhost:8080/whatever
Was getting into our controller by default:
With that config in place, I would expect to get 404 for both:
/whatever
and/my/custom/controller
requests, because in fact there is no mapping for/my/custom/controller
in my app (there is a bean with that name instead).Here is a whole controller's code, no other config is required to reproduce this, just standard spring boot app with this single controller:
The text was updated successfully, but these errors were encountered: