Protocol and runtime expectation for a v8 compliant server implementation (04/2017)
Send-Queue behavior
- message id monotonically increasing (int32)
- bounded by # of messages and byte sizes
- support requeue (retransmit)
- support urgent-messages as a separate queue
Client message behavior
- urgent: real-time delivery at the cost of efficiency
- unreliable: OK to drop
- message id
- retransmitting (in the queue)
- timestamped progress state:
- sent, unsent, retrying, delivered (acked)
- discarding (unreliable), dropped (never to deliver)
- format: [id, [...]]
Protocol state
- last message (array) id
- last message (array) id that has been acked
- last client request id (RID)
- last client message id (map): duplicates possible; gaps allowed (if client decides to drop v.s. retry)
- GET req: RID=rpc
- POST req: TYPE=terminate (client abort) -- duplicate OK
- initial POST: last request id = RID - 1; return ["c", "session-id", "", version, cversion]
- POST req: AID (acked server message id)
- POST resp: [back_channel_exists, last-server-sent-message-id, unacked-outstanding-bytes]
- POST resp: [number chars]\n[array data]
- POST req format (form encoded): [count] [ofs] [req#_name: value] ...
- POST req format: {type: "_badmap"} for messages that can't be serialized on the client side
- GET req: CI (close immediately); t (retry count);
- GET req: AID (acked server message id)
- GET resp: first noop (if nothing queued)
- GET resp format: JSON arrays, length prefixed + "\n"
- Client may append new messages to a retry POST
- Req: SID (session id, if not the first POST)
- First POST: OSID, OAID (for tracking/stats of dropped messages, if reconnecting)
- GET req: TYPE=xmlhttp ...
HTTP detail
- Default C-T: "text/plain; charset=utf-8" Safari: "text/chat; charset=utf-8" (buffering up to 1KB)
- Firefox/IE: GET resp compression disabled ...
- Disable cache
- "X-Frame-Options": "ALLOWALL" (iframe handling)
- Handshake failure: BAD_REQUEST, "Unknown SID"
- Blocked host name: ...
- Initial text block for IE: ...
Channel test
- Disable compression
- Req param: MODE=init
- Init resp: [...] (ignored)
- test req behavior: "11111" (safari buffering); add 1s delay; "2"
- echo X-Client-Wire-Protocol, (may not working due to forward proxies)
Config params
- max. pending messsages: 10,000
- max. pending bytes: 100MB
- max client requests: 2 or 10, 100
- max. bytes per a single GET: 100KB
- max. bytes per flush (back channel): 50KB -- useless
- max. # of messages per POST: 1000
- max. # of unacked messages to hold: 200
- default backchannel inactivity timeout: 60s
- default keep-alive message (noop) interval: 30s
- max. buffered GET open: same as keep-alive, 30s (both are meant to keep connections from being prematurely closed by network)
- wait time before delivering non-urgent data over buffered connections: 15s
- interval to keep (unbuffered) GET open: 45s (60s effectively, only checked with data to send, e.g. noop)
- default delay for channel test: 1000ms
- Clean up (stale connection with no I/O activity) interval: 15 min. Stale (no activity) after 5 min.
Channel state
- Init
- Open
- Closed
Buffered mode
- Buffered
- UnBuffered
- Disconnected
Close reason
- Terminated
- Error
- Inactive timeout
- Stale ??
- Unknown
- Channel not allowed (by application hook)
Commands
- "c" - send connection data
- "noop"
- "stop" - close the channel (abort)
Useful monitoring stats
- missing backchannel, when serving a post
- backchannel data quote
- backchannel reconnect ratio (flaky network)
- backchannel drop and recovery count (I/O error, ISP)
- buffered channels
- interval without backchannel
- rate and interval with max. bytes reached
Misc.
- randomize a value with maximum - nextInt(maximum / 5)
- API for recording dropped messages when abort