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

Fix WebSocket frame concatenation for Netty #3801

Merged
merged 2 commits into from
May 29, 2024
Merged

Conversation

kciesielski
Copy link
Member

When handling incoming WebSocket frames, there was a missing case for a "non-final data frame and no data accumulated".

  1. I added the case and moved frame concatenation to WebSocketFrameConverters, so it's shared between netty-sync and netty-cats
  2. I also added cases where a binary frame comes after a text frame, this is specific to Netty (a WebSocketContinuationFrame is a binary frame that follows a text frame).
  3. I added test cases mentioned in 1. to other backends where they were missing: Vert.X, zio-http, http4s.

BTW it turns out http4s does frame concatenation by itself, regardless of our configuration.

After adding missing cases, there are issues with concatenation in zio-http and vert.x. The stream freezes after receiving first frame in the accumulation. This needs separate investigation.

@kciesielski kciesielski marked this pull request as ready for review May 29, 2024 10:01
@kciesielski kciesielski requested a review from adamw May 29, 2024 10:01
@@ -101,6 +101,8 @@ private[http4s] object Http4sWebSockets {
case (None, f: WebSocketFrame.Pong) => (None, Some(f))
case (None, f: WebSocketFrame.Close) => (None, Some(f))
case (None, f: WebSocketFrame.Data[_]) if f.finalFragment => (None, Some(f))
case (None, f: WebSocketFrame.Text) => (Some(Right(f.payload)), None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed this seems rather basic :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but if http4s concatenates frames by itself, shouldn't we remove this? it's dead code anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let me double check though, maybe there's some kind of switch on the Blaze/Ember level to control this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, turns out that:

  1. Http4s can be configured to not concatenate fragmented frames and not ignore pings/pongs on the level of WebSocketBuilder2:
      .withHttpWebSocketApp(wsb => Router("/" -> wsRoutes(wsb.withDefragment(false).withFilterPingPongs(false)).orNotFound)
  1. This has no effect if used with Blaze, which always automatically defragments and filters pings pongs
  2. It works with Ember though.

I'll remove these stages from Http4sWebSockets and add some documentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can keep our own defragmentation and force wsb.withDefragment(false) to make this Tapir-native switch work on Ember by forcing passing through our concatenation 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ... if it's optional, let's keep the code, and let the user of http4s decide. So I guess the code is good as-is

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has several bugs actually, as I discovered when I switched from Blaze to Ember in tests. Fixes are on the way in a separate PR then ;)

@adamw adamw merged commit cf82f2f into master May 29, 2024
26 checks passed
@adamw adamw deleted the fix-ws-frame-concat branch May 29, 2024 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants