djhfwk 0 Posted yesterday at 03:00 AM (edited) In the current version (V9.4) of TSslWebSocketCli, the OnFrameRcvd event is triggered before the OnConnected event. This is the full set of modifications I made for OverbyteIcsWebSocketCli.pas, and it requires review. I added a new value to TWebSocketState: wssConnected. This state represents the situation where the server has already responded with "101 Switching Protocols", but the internal HttpState has not yet reached httpReady. In TSslWebSocketCli.IsWSConnected, HttpState need to be httpReady. I overrode StateChange to wait for this condition. I’m curious why the httpReady state is always slightly delayed. With this change, OnConnected is now triggered earlier, before OnFrameRcvd, which aligns better with the expected WebSocket event sequence. However, there is still one issue: OnFrameRcvd may be triggered before WSConnect returns. I'm not sure whether this behavior is acceptable or expected. Please advise. Using Demo: OverbyteIcsSnippets as client and OverbyteIcsSslMultiWebServ as server TWebSocketState = (wssHttp, wssConnecting, wssConnected, wssReady); function TSslWebSocketCli.WSConnect: Boolean; begin Result := False; RequestVer := '1.1'; HeaderUpgrade := ''; HeaderConnection := ''; HeaderSecWebSocketAccept := ''; HeaderSecWebSocketProtocol := ''; HeaderAccessControlAllowOrigin := ''; FWSFrameCounter := 0; if (DebugLevel >= DebugConn) then LogEvent('WebSocket: Connecting to: ' + URL); // WSState := wssConnecting; { in case server returns data quickly } Get; // sync request Result:= WSState = wssReady; end; procedure TSslWebSocketCli.StateChange(NewState: THttpState); begin inherited; if (NewState = httpReady) and (WSState = wssConnected) then begin WSState := wssReady; if Assigned(FOnWSConnected) then FOnWSConnected(Self); end; end; procedure TSslWebSocketCli.SocketDataAvailable(Sender: TObject; ErrCode: Word); var Len: Integer; { JK 28.11.2023 } BufPos : Integer; ParsedBytes : Integer; { JK 28.11.2023 end } ServerKey : String; s : AnsiString; KeyComp: Boolean; begin if (NOT (State = httpReady)) OR (WSState <> wssReady) then begin inherited SocketDataAvailable(Sender, ErrCode); // if FReceiveLen >= 2 then // LogEvent('WebSocket: Inherited Recv Raw: ' + IcsTBytesToString(FReceiveBuffer, FReceiveLen)); // !!! TEMP if (WSState <> wssConnecting) then Exit; //The protocol has been upgraded from HTTP to WebSocket. //This is when the connection is truly considered established. if (StatusCode = 101) then begin if SameText(HeaderUpgrade, 'websocket') and SameText(HeaderConnection, 'Upgrade') then begin s := AnsiString(ClientKey + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); ServerKey := String(IcsBase64EncodeA(SHA1ofStr(s))); { V9.1 corrected string cast, V9.4 } KeyComp := (HeaderSecWebSocketAccept = ServerKey); if (NOT KeyComp) and (DebugLevel >= DebugConn) then LogEvent('WebSocket: Server Key Comparison Failed'); end else if (DebugLevel >= DebugConn) then LogEvent('WebSocket: Failed to Upgrade to WebSocket Protocol'); end else if (DebugLevel >= DebugConn) then LogEvent('WebSocket: Failed to Connect: ' + LastResponse); if KeyComp then begin if (DebugLevel >= DebugConn) then LogEvent('WebSocket: Connected OK'); //change the state to wssConnected, then wait httpReady WSState := wssConnected; { in case server returns data quickly } LastReceivedDataTickCount := IcsGetTickCount64; LastSentPingTickCount := 0; if (FWSPingSecs > 0) and (FWSPingSecs < 5) then FWSPingSecs := 5; FPeriodicTimer.Enabled := true; end else WSState := wssHttp; end; ........ OverbyteIcsWebSocketCli.pas Edited yesterday at 06:58 AM by djhfwk Share this post Link to post
Angus Robertson 658 Posted yesterday at 08:17 AM I'll look at your changes, but I rewrote the WSConnect function yesterday, adding an async option so it is no longer blocking, which was a serious anomaly for ICS. I've also changed the ICS server component not to send welcome or other data immediately, before the client has a chance to process the 101 command and switch to Websocket mode. Still testing all this. Angus Share this post Link to post
djhfwk 0 Posted yesterday at 08:57 AM (edited) 41 minutes ago, Angus Robertson said: I'll look at your changes, but I rewrote the WSConnect function yesterday, adding an async option so it is no longer blocking, which was a serious anomaly for ICS. I've also changed the ICS server component not to send welcome or other data immediately, before the client has a chance to process the 101 command and switch to Websocket mode. Still testing all this. Angus This is indeed great news — hats off to the hardworking author of ICS! Edited yesterday at 08:58 AM by djhfwk Share this post Link to post