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

implicit cast failed on reactive.TomcatHttpHandlerAdapter$TomcatServerHttpRequest #15489

Closed
tutufool opened this issue Dec 18, 2018 · 9 comments
Assignees
Labels
for: external-project For an external project and not something we can fix status: superseded An issue that has been superseded by another

Comments

@tutufool
Copy link

tutufool commented Dec 18, 2018

When upgrade to spring boot 2.1.1, the newly introduced spring-web-5.1.3.RELEASE gives me exceptions:

 java.lang.IllegalArgumentException: Can not set org.apache.catalina.connector.Request field org.apache.catalina.connector.RequestFacade.request to org.apache.catalina.core.ApplicationHttpRequest
 	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) ~[na:1.8.0_20]
 	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) ~[na:1.8.0_20]
 	at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58) ~[na:1.8.0_20]
 	at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36) ~[na:1.8.0_20]
 	at java.lang.reflect.Field.get(Field.java:387) ~[na:1.8.0_20]
 	at org.springframework.util.ReflectionUtils.getField(ReflectionUtils.java:169) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
 	at org.springframework.http.server.reactive.TomcatHttpHandlerAdapter$TomcatServerHttpRequest.createTomcatHttpHeaders(TomcatHttpHandlerAdapter.java:106) ~[spring-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
 	at org.springframework.http.server.reactive.TomcatHttpHandlerAdapter$TomcatServerHttpRequest.<init>(TomcatHttpHandlerAdapter.java:99) ~[spring-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
 	at org.springframework.http.server.reactive.TomcatHttpHandlerAdapter.createRequest(TomcatHttpHandlerAdapter.java:68) ~[spring-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
 	at org.springframework.http.server.reactive.ServletHttpHandlerAdapter.service(ServletHttpHandlerAdapter.java:171) ~[spring-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384) ~[tomcat-embed-core-9.0.13.jar:9.0.13]
 	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312) ~[tomcat-embed-core-9.0.13.jar:9.0.13]

related code:

private static HttpHeaders createTomcatHttpHeaders(HttpServletRequest request) {
	org.apache.catalina.connector.Request connectorRequest = (org.apache.catalina.connector.Request)
		ReflectionUtils.getField(COYOTE_REQUEST_FIELD, request);
	Assert.state(connectorRequest != null, "No Tomcat connector request");
	Request tomcatRequest = connectorRequest.getCoyoteRequest();
	TomcatHeadersAdapter headers = new TomcatHeadersAdapter(tomcatRequest.getMimeHeaders());
	return new HttpHeaders(headers);
}

The code assuming pass in request is an org.apache.catalina.connector.RequestFacade.
But actually it's org.apache.catalina.core.ApplicationHttpRequest.

@bclozel bclozel self-assigned this Dec 18, 2018
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 18, 2018
@bclozel
Copy link
Member

bclozel commented Dec 18, 2018

This is likely to be a bug in Spring Framework.
Could you provide more information on how to reproduce that? Do you have a sample application I can run?

@bclozel bclozel added the status: waiting-for-feedback We need additional information before we can continue label Dec 18, 2018
@tutufool
Copy link
Author

@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 Dec 18, 2018
@bclozel
Copy link
Member

bclozel commented Dec 18, 2018

Thanks for the repro.
I see you're trying to use org.apache.tomcat.websocket.server.WsFilter in your application. I've got a couple of comments about that first:

  • For websocket support, you should use what's provided by Spring WebFlux already
  • In my opinion, it's a bad idea to use Servlet filters on a WebFlux application. Since WebFlux is using the Tomcat container in async IO mode (note: not just async), nothing should read or write to the request/response in a blocking way. Most filters out there won't work.

With that in mind, there might be a problem still in Spring Framework since we shouldn't maybe enforce the total absence of Servlet Filters. Let me get back to you on that.

@tutufool
Copy link
Author

I didn't specify org.apache.tomcat.websocket.server.WsFilter by my own, not sure which component/starter bring it in.

My application contains 2 parts:

  1. biz logic served via webflux: RestControllers + WebFilters
  2. legacy servlet based admin console: pure servlet + it's own servlet filters

They're both in the same tomcat container, but will not interfere with each other.

@poutsma
Copy link
Contributor

poutsma commented Dec 19, 2018

I've created a JIRA for Spring Framework here: https://jira.spring.io/browse/SPR-17611

@poutsma
Copy link
Contributor

poutsma commented Dec 19, 2018

@wilkinsona
Copy link
Member

Thanks, @poutsma. We're building against Framework 5.1.4 snapshots now (as part of #15493) so there's nothing more to do here on the Boot side.

@wilkinsona wilkinsona added for: external-project For an external project and not something we can fix status: superseded An issue that has been superseded by another and removed status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged labels Dec 19, 2018
@bclozel
Copy link
Member

bclozel commented Dec 19, 2018

Thanks @poutsma !

@tutufool the WsFilter seems to be deployed anyway in your arrangement. Even though this issue is fixed on the Framework side, my warning still stands. Servlet async I/O is a very different beast, and mixing blocking + non-blocking IO through filters in the same request/response processing is likely to cause issues.

@tutufool
Copy link
Author

tutufool commented Dec 24, 2018

@bclozel Thanks for your reminding.

Is there a way to explicitly exclude WsFilter in my case?
I guess WsFilter is default enabled for reactive mode.

However, like I said, my case is special, I have to support both case within same tomcat container:

  1. biz logic served via webflux: RestControllers + WebFilters (non-blocking)

  2. legacy servlet based admin console: pure servlet + it's own servlet filters (blocking)

1 and 2 are different request/response processing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: superseded An issue that has been superseded by another
Projects
None yet
Development

No branches or pull requests

5 participants