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

Response with an invalid content type hangs when using WebFlux with Jetty #23553

Closed
wilkinsona opened this issue Aug 31, 2019 · 2 comments
Closed
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug
Milestone

Comments

@wilkinsona
Copy link
Member

Affects: 5.1.9

I discovered this while adding a test for spring-projects/spring-boot#18027 that covered all of Boot's reactive web servers. I've tried to reproduce it in a small standalone example but didn't manage to do so. Sorry. It can be reproduced by moving this test to the superclass and then running JettyReactiveWebServerFactoryTests. You should see the block time out after 30 seconds.

@rstoyanchev
Copy link
Contributor

rstoyanchev commented Sep 11, 2019

I see the following output:

2019-09-11 17:45:20.027 TRACE ${sys:PID} --- [tp2017797638-18] _.s.h.s.r.AbstractListenerReadPublisher  : [7543329c] onAllDataRead
2019-09-11 17:45:20.027 TRACE ${sys:PID} --- [tp2017797638-18] .s.r.AbstractListenerWriteFlushProcessor : [7543329c] Received request to cancel
2019-09-11 17:45:20.027 TRACE ${sys:PID} --- [tp2017797638-18] .s.r.AbstractListenerWriteFlushProcessor : [7543329c] Received onComplete
17:45:20.027 [qtp2017797638-18] WARN org.eclipse.jetty.server.HttpChannelState - java.lang.IllegalStateException: UNSUBSCRIBED while invoking onComplete liste
ner org.springframework.http.server.reactive.ServletServerHttpResponse$ResponseAsyncListener@9163a1
17:45:20.028 [qtp2017797638-18] DEBUG org.eclipse.jetty.server.HttpChannelState - 
java.lang.IllegalStateException: UNSUBSCRIBED
        at org.springframework.http.server.reactive.AbstractListenerWriteFlushProcessor$State.onComplete(AbstractListenerWriteFlushProcessor.java:378)
        at org.springframework.http.server.reactive.AbstractListenerWriteFlushProcessor.onComplete(AbstractListenerWriteFlushProcessor.java:127)
        at org.springframework.http.server.reactive.ServletServerHttpResponse$ResponseAsyncListener.onComplete(ServletServerHttpResponse.java:237)
        at org.eclipse.jetty.server.HttpChannelState$4.run(HttpChannelState.java:906)
        at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1392)
        at org.eclipse.jetty.server.HttpChannelState.runInContext(HttpChannelState.java:1134)
        at org.eclipse.jetty.server.HttpChannelState.onComplete(HttpChannelState.java:923)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:522)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:268)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
        at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918)
        at java.lang.Thread.run(Thread.java:748)

I think the issue is we're making an implicit assumption in the Servlet to Reactive Streams bridge that there won't be an onComplete signal before there is a subscriber which happens right after handling. However if handling happens immediately in the same thread and gets as far as writing which in turn causes an issue, we may get an error or completion notification from the Servlet AsyncListener even before the actual subscribe. So we need to anticipate that and not raise the above ISE.

@rstoyanchev rstoyanchev self-assigned this Sep 11, 2019
@rstoyanchev rstoyanchev added in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 11, 2019
@rstoyanchev rstoyanchev added this to the 5.1.10 milestone Sep 11, 2019
rstoyanchev added a commit that referenced this issue Sep 12, 2019
On a Servlet container a completion notification may come at any time
even in the UNSUBSCRIBED state, i.e. before the write Publisher has
called onSubscribe.

See: gh-23553
@rstoyanchev
Copy link
Contributor

The real reason turned out to be that when Content-Length is set, it is reflected right away since we delegate from HttpHeaders to the Jetty response headers through an adapter. However later in JettyServerHttpResponse#applyHeaders we run into an error when parsing the media type which leads to Jetty setting the response to 500 and completing , but the content-length is still set and so the client hangs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants