[undertow-dev] websocket per-message compression & design q

peter royal peter.royal at pobox.com
Mon Aug 10 14:31:52 EDT 2015


Hi!

I'm trying to debug the problems I've encountered after enabling 
per-message compression on websockets in 1.2, 
https://issues.jboss.org/browse/UNDERTOW-508

One thing I've noticed is that there's an entirely different code path 
used inside of WebSocket07FrameSinkChannel whenever extensions are 
enabled. I was trying to think of how to refactor how extensions are 
applied so that it would be a path that is always-on, and thus hopefully 
subject to more scrutiny and use.

Conceptually, extensions are transformations to the ByteBuffer that 
makes up a message payload. I think the internals might be a bit clearer 
if they were treated as that, and then always applied. (the 
ExtensionByteBuffer class is something I'd want to eliminate).

 From an internal API point of view, calls to write on a websocket are 
mostly made via the WebSockets class, and then a couple of places that 
use the StreamSinkFrameChannel (SSFC) over a longer period of time for 
partial messages and streams in the WS JSR implementation.

For sending, the GatheringByteChannel APIs are used to represent writing 
a message. A collection of writes to a single SSFC will result in 1..n 
WS message fragments depending on how large the buffers returned from 
the allocator are. When using extensions, there are a bunch of 
ergonomics regarding the return value from write and remaining bytes in 
the provided buffers to enable

For the WebSockets send methods, all the data to send is already in 
memory, and the methods just spin or wait over the SSFC writing 
fragments until all the data is sent. Then there are the blocking APIs 
in the JSR that send a single fragment and wait for it to be flushed.

I think it might be cleaner to push some of that responsibility from the 
WebSockets utility class into the WebSocket07FrameSinkChannel. For the 
non-blocking cases, that'd be merging the following two lines from 
WebSockets into a single call,

     StreamSinkFrameChannel channel = wsChannel.send(type, totalData);
     WebSockets.sendData(data, wsChannel, callback, channel, null, 
timeoutmillis);

The channel can then apply the extensions to data and do the appropriate 
thing. Similar changes would happen to the blocking methods.

I realize this is a bit ramble-y, but I wanted to at least get some of 
my thoughts out there. I'm eager to get WS extensions working fully, and 
thought that re-architecting how the sending of WS messages happen might 
make the code less brittle and easier to maintain

-pete



-- 
(peter.royal|osi)@pobox.com - http://fotap.org/~osi


More information about the undertow-dev mailing list