Skip to content
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

bug with accessing RestController endpoints due to #35426 ? #43885

Open
FyiurAmron opened this issue Jan 20, 2025 · 4 comments
Open

bug with accessing RestController endpoints due to #35426 ? #43885

FyiurAmron opened this issue Jan 20, 2025 · 4 comments
Labels
for: team-meeting An issue we'd like to discuss as a team to make progress status: waiting-for-triage An issue we've not yet triaged

Comments

@FyiurAmron
Copy link

FyiurAmron commented Jan 20, 2025

Impossible for me to say if this is a bug or a feature/documented change, hence the ticket. Facts:

test snippets:

@RestController
@RequestMapping("/api")
class TestController {

    @PostMapping("endpoint")
    fun endpoint(): HttpEntity<*> {
        return ResponseEntity.EMPTY
    }

}
management:
  endpoints.web:
    base-path: "/"
    path-mapping:
      health: "/"

results for 3.2.1:

GET -> 405
POST -> 200
PUT -> 405

results for 3.2.2:

GET -> 404
POST -> 405
PUT -> 405

Further details:

  • The config shown doesn't throw any exception and never did.
  • I also didn't notice any kind of warnings emitted with it (went through logs with DEBUG log level)
  • Changing health from / to e.g. /foo "fixes" the behaviour (i.e. the endpoints start to work again)
  • Changing base-path to anything else than / (e.g. /foo) in this case triggers: Ambiguous mapping. Cannot map 'Actuator root web endpoint' method Actuator root web endpoint to {GET [/foo], produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}: There is already 'Actuator web endpoint 'health'' bean method

My take on it is:

  • If this config (i.e. both base-path and at least one of the mappings equal to /) is deemed invalid, it should throw an exception during bean init for this particular case, like the case with non-/ base and / endpoint. However, the valid use case for this was hiding the "root" actuator endpoint AFAIK.
  • If this config is deemed valid, the RestController should still work when that config is used.

With all honesty, I'd say this is a bug, mainly due to backwards-compatibility reasons. The code in question did work in previous patches in the same major/minor release (AFAIK both 3.2 and 3.1 are affected in this way), and a patch shouldn't introduce breaking changes that ain't backwards-compatible even if they are just fixing some abuses or corner cases (and the code shown isn't even really one of those I'd argue). If it would introduced purely with a minor increase and clearly documented, only the lack of exception thrown would be a problem here.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 20, 2025
@FyiurAmron FyiurAmron changed the title possible bug with accessing RestController endpoints due to #35426 bug with accessing RestController endpoints due to #35426 ? Jan 20, 2025
@wilkinsona
Copy link
Member

wilkinsona commented Jan 20, 2025

Thanks for the report. Unfortunately, I don't think I understand the problem as currently described. Your snippet shows the use of @RestController which is separate from the Actuator endpoint infrastructure. Perhaps you meant @RestControllerEndpoint or perhaps you are saying that the Actuator and its health endpoint being mapped to / prevents access to a standard @RestController endpoint on /api? To help to remove this confusion, please provide a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

Also, please note that Spring Boot 3.2.x is no longer supported. Any sample that you share with us should use 3.3.7 or 3.4.1 to demonstrate the problem.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jan 20, 2025
@FyiurAmron
Copy link
Author

FyiurAmron commented Jan 20, 2025

perhaps you are saying that the Actuator and its health endpoint being mapped to / prevents access to a standard @RestController endpoint on /api?

this, precisely.

To help to remove this confusion, please provide a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

Sure thing. Gimme a sec.

Also, please note that Spring Boot 3.2.x is no longer supported. Any sample that you share with us should use 3.3.7 or 3.4.1 to demonstrate the problem.

Sure, no problemo, as this problem also affects 3.4.1; basically, everything higher than 3.2.1 or 3.1.7 (including >=3.1.8+, >=3.2.2, >=3.3.0 and >= 3.4.0) is affected.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jan 20, 2025
@FyiurAmron
Copy link
Author

FyiurAmron commented Jan 20, 2025

@wilkinsona

spring-boot-actuator-vs-restcontroller-problem-43885-main.zip

Here you go mate :) Ping me if anything else is missing, but I guess this is as MCVE as it gets :)

@wilkinsona
Copy link
Member

Thank you.

The problem's occurring because there's a clash at the path level between the mappings for the health endpoint and the mapping for your @RestController:

2025-01-21T10:13:12.592Z TRACE 61191 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
	t.v.b.Controller:
	{POST [/api/endpoint]}: endpoint()
…
2025-01-21T10:13:12.732Z TRACE 61191 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET [/**], produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(jakarta.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
2025-01-21T10:13:12.733Z TRACE 61191 --- [           main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Register "{GET [/ || ], produces [application/vnd.spring-boot.actuator.v3+json || application/vnd.spring-boot.actuator.v2+json || application/json]}" to java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(jakarta.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)

WebMvcEndpointHandlerMapping is called first by the dispatcher servlet. The path match combined with the HTTP method mismatch results in a HttpRequestMethodNotSupportedException being thrown and a 405 response. This doesn't occur in 3.2.1 because of a bug in how to Actuator created its mappings with the health endpoint being mapped to //** instead of /**. This causes the path match to be missed.

The combination of a patch match and a method mismatch is detected in handleNoMatch in RequestMappingInfoHandlerMapping from where the HttpRequestMethodNotSupportedException is thrown. We may be able to accommodate mappings for both POST [/api/endpoint] and GET [/**] by overriding handleNoMatch in AbstractWebMvcEndpointHandlerMapping and returning null. This would then give subsequent handler mappings an opportunity to provide a match. Spring Data REST's RepositoryRestHandlerMapping does exactly this, for similar reasons I would guess.

I'd like to discuss this with the rest of the team as web request matching is a complex area. I may well be overlooking a risk in overriding handleNoMatch to return null.

@wilkinsona wilkinsona added for: team-attention An issue we'd like other members of the team to review for: team-meeting An issue we'd like to discuss as a team to make progress and removed status: feedback-provided Feedback has been provided for: team-attention An issue we'd like other members of the team to review labels Jan 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: team-meeting An issue we'd like to discuss as a team to make progress status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

3 participants