WebSocket client API
Joakim Erdfelt
joakim.erdfelt at gmail.com
Mon Sep 14 19:48:51 UTC 2015
Decided to take a stab at a list of "requirements"...
What do people want from a WebSocket client?
First, the baseline requirements:
(If you don't provide 100% of this list you have a inadequate
implementation):
Initiate a connection
- simple connect (URI)
- advanced connect (HttpClient)
- ability to manage SSL configuration
- ability to manage cookies
- ability to manage authentication
- ability to manage arbitrary HTTP headers
- configure websocket handshake request values
- subprotocol list
- extension list
- origin
- configure websocket implementation behavior (necessary for working
with whole message receive!)
- max text message size (ignored for streaming behavior)
- max binary message size (ignored for streaming behavior)
Events:
- connected (event / single)
- received data [TEXT|BINARY] (event / [0..n])
- receive whole TEXT
void onText(String)
- receive whole BINARY
void onBinary(ByteBuffer buf)
- received control [PING|PONG] (event / [0..n])
- valid signatures
- void onPing(ByteBuffer payload)
Note: implementation automatically responds to received PING with
PONG of identical payload
- void onPong(ByteBuffer payload)
- closed (event / single / terminal)
- knowledge about why?
- was this a local close or remote close?
- was the close clean? (abnormal)
- I/O error (event / [0..n])
- connection timeout
- unable to write (connection closed?)
- bad data (protocol violation detected locally)
Queries:
- is still open/connected
- remote InetAddress
- local InetAddress
- remote endpoint URI
- websocket handshake requested
- subprotocol list (optional)
- extension list (optional)
- origin (optional)
- websocket handshake negotiated
- subprotocol selected
- extensions in use
Actions:
- send data
- send whole TEXT
Local UTF8 validation required!
- valid signatures
.send(java.lang.CharSequence text)
.send(java.nio.CharBuffer textBuffer)
- send whole BINARY
- valid signatures
.send(byte[] buf)
.send(byte[] buf, int offset, int len)
.send(java.nio.ByteBuffer)
- send control
- send PING
- close
- friendly close actions
.close() - no status code, no reason.
an IOException is not possible from this use.
Always results in close and/or disconnect.
.close(int) - status code only, no reason.
an IOException can result from protocol violation
from bad statusCode use (1005/1006)
.close(int, String) - status code and reason.
an IOException can result from protocol violation
Note: "close" event only notified if remote has closed too.
- harsh close
.disconnect()
Note: "close" event is called with abnormal close (1006)
Next: the advanced topics:
Events:
- receive partial TEXT
void onText(String partial, boolean finished)
Note: implementation needs to be UTF8 codepoint aware to only notify
whole codepoints, keeping partial codepoints for next receive.
it is possible to have an empty partial with finished==true
- receive partial BINARY
void onBinary(ByteBuffer partial, boolean finished)
Note: it is possible to have an empty partial with finished==true
Actions:
- send async Whole TEXT
MUST have backpressure support!
consider JSR166 java.util.concurrent.Flow
- send async Whole BINARY
MUST have backpressure support!
consider JSR166 java.util.concurrent.Flow
- send stream TEXT
Proposed signature:
.sendTextStream(ReadableByteChannel channel)
Note: implementation makes the call when to read from the provided
channel and when not to based on backpressure
Bonus: wire up existing nio channels
- send stream BINARY
Proposed signature:
.sendBinaryStream(ReadableByteChannel channel)
Note: implementation makes the call when to read from the provided
channel and when not to based on backpressure
Bonus: you can wire up nio channels just like existing nio
behavior
Really advanced topics:
Extensions:
- Send TEXT and Send BINARY methods should have the ability to provide
hints to the outgoing frame extension handling mechanism.
- MUST support standard RFC Extension negotiation.
- Local Extensions should be supported as well (for extensions that
don't
need negotiation with the remote, but can run entirely on local side)
eg: Fragment extension (automatically break up large messages by
upper fragment
size).
Identity extensions (to have 3rd party libraries pay attention to
what is being sent)
Debug extensions / Multicast send/receive / etc ...
Extension SPI:
- This is possible, Jetty introduced its SPI in Jetty 9.1.0 (Nov 2013)
Proposed API:
public interface IncomingFrames {
void incomingFrame(Frame);
}
public interface OutgoingFrames {
void outgoingFrame(Frame, CallbackFuture);
}
public interface Extension extends IncomingFrames, OutgoingFrames{
String getToken();
String getParams();
String negotiate(String params);
int getRSV();
void setNextIncomingFrames(IncomingFrames incoming);
void setNextOutgoingFrames(OutgoingFrames outgoing);
}
What you need to provide:
- Extension Negotiation
- Generate Extension ID (token/name + params)
- Given Requested Extension ID (token/name + params), determine
negotiation
Proposed pseudo code for implementation:
IncomingFrames nextIncoming = getFrameParser();
OutgoingFrames nextOutgoing = getFrameGenerator();
ListIterator<Extension> exts:
response.getExtensions().listIterator();
// Connect outgoings
while(exts.hasNext())
{
Extension ext = exts.next();
ext.setNextOutgoingFrames(nextOutgoing);
nextOutgoing = ext;
}
// Connect incomings
while(exts.hasPrevious())
{
Extension ext = exts.previous();
ext.setNextIncomingFrames(nextIncoming);
nextIncoming = ext;
}
// Wire up to connection
connection.setOutgoingFrames(nextOutgoing);
connection.setIncomingFrames(nextIncoming);
- Incoming Frame manipulation
The incoming frame can result in [0..n]
nextIncoming.incomingFrame(Frame) calls
- Outgoing Frame manipulation
The outgoing frame can result in [0..n]
nextOutgoing.outgoingFrame(Frame,CallbackFuture) calls.
Note: if extension fragments the frame further, the Callback
for completion should also be handled intelligently for the
finished frame write.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/net-dev/attachments/20150914/89f77283/attachment.html>
More information about the net-dev
mailing list