fpwebsocket.pp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910
  1. {
  2. $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 2021 - by the Free Pascal development team
  5. Abstract websocket protocol implementation - objects only
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit fpwebsocket;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$mode objfpc}
  16. {$h+}
  17. {$modeswitch advancedrecords}
  18. {$modeswitch typehelpers}
  19. interface
  20. {$IFDEF FPC_DOTTEDUNITS}
  21. uses
  22. System.Classes, System.SysUtils, System.Net.Sockets, System.Net.Ssockets;
  23. {$ELSE FPC_DOTTEDUNITS}
  24. uses
  25. Classes, SysUtils, sockets, ssockets;
  26. {$ENDIF FPC_DOTTEDUNITS}
  27. Const
  28. SSecWebSocketGUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
  29. SSecWebsocketProtocol = 'Sec-WebSocket-Protocol';
  30. SSecWebsocketVersion = 'Sec-WebSocket-Version';
  31. SSecWebsocketExtensions = 'Sec-WebSocket-Extensions';
  32. SSecWebsocketKey = 'Sec-WebSocket-Key';
  33. SSecWebsocketAccept = 'Sec-WebSocket-Accept';
  34. MinFrameSize = 4;
  35. DefaultWebSocketVersion = 13;
  36. // Opcodes
  37. FlagReserved = $F;
  38. FlagContinuation = $0;
  39. FlagText = $1;
  40. FlagBinary = $2;
  41. FlagClose = $8;
  42. FlagPing = $9;
  43. FlagPong = $A;
  44. // For SVR etc.
  45. FlagTwoBytes = 126;
  46. FlagEightBytes = 127;
  47. FlagFinalFrame : Byte = $80;
  48. FlagMasked : Byte = $80;
  49. FlagLengthMask : Byte = $7F;
  50. FlagRES1 = $40;
  51. FlagRES2 = $20;
  52. FlagRES3 = $10;
  53. CLOSE_NORMAL_CLOSURE = 1000;
  54. CLOSE_GOING_AWAY = 1001;
  55. CLOSE_PROTOCOL_ERROR = 1002;
  56. CLOSE_UNSUPORTED_DATA = 1003;
  57. CLOSE_RESERVER = 1004;
  58. CLOSE_NO_STATUS_RCVD = 1005;
  59. CLOSE_ABNORMAL_CLOSURE = 1006;
  60. CLOSE_INVALID_FRAME_PAYLOAD_DATA = 1007;
  61. CLOSE_POLICY_VIOLATION = 1008;
  62. CLOSE_MESSAGE_TOO_BIG = 1009;
  63. CLOSE_MANDRATORY_EXT = 1010;
  64. CLOSE_INTERNAL_SERVER_ERROR = 1011;
  65. CLOSE_TLS_HANDSHAKE = 1015;
  66. type
  67. EWebSocket = Class(Exception);
  68. EWSHandShake = class(EWebSocket);
  69. TFrameType = (ftContinuation,ftText,ftBinary,ftClose,ftPing,ftPong,ftFutureOpcodes);
  70. TFrameTypes = Set of TFrameType;
  71. TFrameSequence = (fsFirst,fsContinuation,fsLast);
  72. TFrameSequences = Set of TFrameSequence;
  73. TIncomingResult = (irNone, // No data waiting
  74. irWaiting, // Data waiting
  75. irOK, // Data was waiting and handled
  76. irClose // Data was waiting, handled, and we must disconnect (CloseState=csClosed)
  77. );
  78. { TFrameTypeHelper }
  79. TFrameTypeHelper = Type helper for TFrametype
  80. private
  81. function GetAsFlag: Byte;
  82. procedure SetAsFlag(AValue: Byte);
  83. Public
  84. Property asFlag : Byte Read GetAsFlag Write SetAsFlag;
  85. end;
  86. { TWSHeaders }
  87. TWSHeaders = class
  88. private
  89. FRawHeaders: TStrings;
  90. FResource: String;
  91. Protected
  92. Function GetS(aIdx : Integer) : String;
  93. procedure SetS(AIndex: Integer; const AValue: string);
  94. Function GetH(const aName : string) : String;
  95. procedure SetH(const aName, aValue: string);
  96. Public
  97. Const
  98. WSHeaderNames : Array[0..8] of string
  99. = ('Host','Origin','Connection','Upgrade',SSecWebSocketProtocol,
  100. SSecWebSocketVersion,SSecWebSocketExtensions,SSecWebSocketKey,
  101. SSecWebSocketAccept);
  102. public
  103. constructor Create(const aResource : String; const AHeaderList: TStrings); virtual;
  104. Destructor Destroy; override;
  105. Property RawHeaders : TStrings Read FRawHeaders;
  106. property Resource : String Read FResource Write FResource;
  107. property Host: string Index 0 read GetS Write SetS;
  108. property Origin: string Index 1 read GetS Write SetS;
  109. property Connection: string Index 2 read GetS Write SetS;
  110. property Upgrade: string Index 3 read GetS Write SetS;
  111. property Protocol: string Index 4 read GetS Write SetS;
  112. property Version: string Index 5 read GetS Write SetS;
  113. property Extensions : String Index 6 read GetS Write SetS;
  114. property Key: string Index 7 read GetS Write SetS;
  115. end;
  116. { TWSHandShakeRequest }
  117. TWSHandShakeRequest = Class(TWSHeaders)
  118. private
  119. FPort: Word;
  120. Public
  121. Constructor Create(const aResource : string; const aExtraHeaders : TStrings); override;
  122. class function GenerateKey: String; static;
  123. Procedure ToStrings(aHeaders : TStrings);
  124. Property Port : Word Read FPort Write FPort;
  125. End;
  126. { TWSHandShakeResponse }
  127. TWSHandShakeResponse = Class (TWSHeaders)
  128. private
  129. FHTTPVersion: String;
  130. FStatusCode: Integer;
  131. FStatusText: String;
  132. Public
  133. Constructor Create(const aResource : string; const aExtraHeaders : TStrings); override;
  134. Procedure ToStrings(aHandShake : TWSHandshakeRequest; aResponse : TStrings; AddStatusLine : Boolean);
  135. Property HTTPVersion : String Read FHTTPVersion Write FHTTPVersion;
  136. Property StatusCode : Integer Read FStatusCode Write FStatusCode;
  137. Property StatusText : String Read FStatusText Write FSTatusText;
  138. property Accept : String Index 8 read GetS Write SetS;
  139. End;
  140. {$INTERFACES CORBA}
  141. { IWSTransport }
  142. IWSTransport = Interface
  143. // Check if transport can read data
  144. Function CanRead(aTimeOut: Integer) : Boolean;
  145. // Read length of buffer bytes. Raise exception if no data read
  146. Procedure ReadBuffer (aBytes : TBytes);
  147. // Read at most aCount bytes into buffer. Return number of bytes actually read, set length of buffer to actually read
  148. function ReadBytes (var aBytes : TBytes; aCount : Integer) : Integer;
  149. // Write at most aCount bytes.
  150. function WriteBytes (aBytes : TBytes; aCount : Integer) : Integer;
  151. // Write complete buffer. Raise exception if not all bytes were written.
  152. Procedure WriteBuffer (aBytes : TBytes);
  153. function ReadLn : String;
  154. function PeerIP: string;
  155. function PeerPort: word;
  156. end;
  157. { TWSSocketHelper }
  158. TWSSocketHelper = Class (TObject,IWSTransport)
  159. Private
  160. FSocket : TSocketStream;
  161. Public
  162. Constructor Create (aSocket : TSocketStream);
  163. Function CanRead(aTimeOut: Integer) : Boolean;
  164. function PeerIP: string; virtual;
  165. function PeerPort: word; virtual;
  166. function ReadLn : String; virtual;
  167. function ReadBytes (var aBytes : TBytes; aCount : Integer) : Integer; virtual;
  168. Procedure ReadBuffer (aBytes : TBytes); virtual;
  169. function WriteBytes (aBytes : TBytes; aCount : Integer) : Integer; virtual;
  170. Procedure WriteBuffer (aBytes : TBytes);
  171. Property Socket : TSocketStream Read FSocket;
  172. end;
  173. { TWSTransport }
  174. TWSTransport = class(TObject, IWSTransport)
  175. Private
  176. FHelper : TWSSocketHelper;
  177. FSocketClosed: boolean;
  178. FStream : TSocketStream;
  179. function GetSocket: TSocketStream;
  180. Public
  181. Constructor Create(aStream : TSocketStream);
  182. Destructor Destroy; override;
  183. Procedure CloseSocket;
  184. Property Helper : TWSSocketHelper Read FHelper Implements IWSTransport;
  185. Property Socket : TSocketStream Read GetSocket;
  186. Property SocketClosed: boolean read FSocketClosed;
  187. end;
  188. { TWSFramePayload }
  189. TWSFramePayload = record
  190. DataLength: QWord;
  191. // Data is unmasked
  192. Data: TBytes;
  193. MaskKey: dword;
  194. Masked: Boolean;
  195. Procedure ReadData(var Content : TBytes; aTransport : IWSTransport);
  196. Procedure Read(buffer: TBytes; aTransport : IWSTransport);
  197. class procedure DoMask(var aData: TBytes; Key: DWORD); static;
  198. class procedure CopyMasked(SrcData: TBytes; var DestData: TBytes; Key: DWORD; aOffset: Integer); static;
  199. class function CopyMasked(SrcData: TBytes; Key: DWORD) : TBytes; static;
  200. end;
  201. { TWSFrame }
  202. TWSFrame = Class
  203. private
  204. FFrameType: TFrameType;
  205. FFinalFrame: Boolean;
  206. FRSV: Byte;
  207. FPayload : TWSFramePayload;
  208. FReason: WORD;
  209. protected
  210. function Read(aTransport: IWSTransport): boolean;
  211. function GetAsBytes : TBytes; virtual;
  212. Public
  213. // Read a message from transport. Returns Nil if the connection was closed when reading.
  214. class function CreateFromStream(aTransport : IWSTransport): TWSFrame;
  215. public
  216. constructor Create(aType: TFrameType; aIsFinal: Boolean; APayload: TBytes; aMask : Integer = 0); overload; virtual;
  217. constructor Create(Const aMessage : UTF8String; aMask : Integer = 0); overload; virtual;
  218. constructor Create(aType: TFrameType; aIsFinal: Boolean = True; aMask: Integer = 0); overload; virtual;
  219. property Reserved : Byte read FRSV write FRSV;
  220. property FinalFrame: Boolean read FFinalFrame write FFinalFrame;
  221. property Payload : TWSFramePayload Read FPayload Write FPayLoad;
  222. property FrameType: TFrameType read FFrameType;
  223. property Reason: WORD read FReason;
  224. Property AsBytes : TBytes Read GetAsBytes;
  225. end;
  226. TWSFrameClass = Class of TWSFrame;
  227. { TWSMessage }
  228. TWSMessage = record
  229. private
  230. function GetAsString: UTF8String;
  231. function GetAsUnicodeString: UnicodeString;
  232. Public
  233. PayLoad : TBytes;
  234. Sequences : TFrameSequences;
  235. IsText : Boolean;
  236. // Use these only when IsText is true (PayLoad contains valid UTF-8).
  237. // You may use them when IsText is false, but only if you know there is valid UTF-8 in payload.
  238. // Return Payload as a UTF8 string
  239. Property AsString : UTF8String Read GetAsString;
  240. // Return Payload as a UTF8 string
  241. Property AsUTF8String : UTF8String Read GetAsString;
  242. // Return Payload (assumed to contain valid UTF8) as a UTF16 string
  243. Property AsUnicodeString : UnicodeString Read GetAsUnicodeString;
  244. end;
  245. TWSMessageEvent = procedure(Sender: TObject; const aMessage : TWSMessage) of object;
  246. TWSControlEvent = procedure(Sender: TObject; aType : TFrameType; const aData: TBytes) of object;
  247. TCloseState = (csNone,csSent,csReceived,csClosed);
  248. TCloseStates = Set of TCloseState;
  249. TWSOption = (woPongExplicit, // Send Pong explicitly, not implicitly.
  250. woCloseExplicit, // Send Close explicitly, not implicitly.
  251. woIndividualFrames, // Send frames one by one, do not concatenate.
  252. woSkipUpgradeCheck, // Skip handshake "Upgrade:" HTTP header cheack.
  253. woSkipVersionCheck, // Skip handshake "Sec-WebSocket-Version' HTTP header check.
  254. woSendErrClosesConn // Don't raise an exception when writing to a broken connection
  255. );
  256. TWSOptions = set of TWSOption;
  257. { TWSConnection }
  258. TWSConnection = class
  259. Private
  260. class var _ConnectionCount : {$IFDEF CPU64}QWord{$ELSE}Cardinal{$ENDIF};
  261. private
  262. FAutoDisconnect: Boolean;
  263. FConnectionID: String;
  264. FFreeUserData: Boolean;
  265. FOnDisconnect: TNotifyEvent;
  266. FOutgoingFrameMask: Integer;
  267. FOwner: TComponent;
  268. FUserData: TObject;
  269. FWebSocketVersion: Integer;
  270. FInitialOpcode : TFrameType;
  271. FMessageContent : TBytes;
  272. FHandshakeRequest: TWSHandShakeRequest;
  273. FOnMessageReceived: TWSMessageEvent;
  274. FOnControl: TWSControlEvent;
  275. FCloseState : TCloseState;
  276. FOptions: TWSOptions;
  277. Function GetPeerIP : String;
  278. Function GetPeerPort : word;
  279. protected
  280. procedure AllocateConnectionID; virtual;
  281. Procedure SetCloseState(aValue : TCloseState); virtual;
  282. Procedure DoDisconnect; virtual; abstract;
  283. // Read message from connection. Return False if connection was closed.
  284. function DoReadMessage: Boolean;
  285. procedure DispatchEvent(aInitialType : TFrameType; aFrame: TWSFrame; aMessageContent: TBytes);
  286. Procedure SetHandShakeRequest(aRequest : TWSHandShakeRequest);
  287. Function HandleIncoming(aFrame: TWSFrame) : Boolean; virtual;
  288. function GetHandshakeCompleted: Boolean; virtual; abstract;
  289. Function GetTransport : IWSTransport; virtual; abstract;
  290. property Owner : TComponent Read FOwner;
  291. function IsValidUTF8(aValue: TBytes): boolean;
  292. Public
  293. Type
  294. TConnectionIDAllocator = Procedure(out aID : String) of object;
  295. class var IDAllocator : TConnectionIDAllocator;
  296. Public
  297. Constructor Create(aOwner : TComponent; aOptions : TWSOptions); virtual;
  298. destructor Destroy; override;
  299. // Extract close data
  300. Class Function GetCloseData(aBytes : TBytes; Out aReason : String) : Word;
  301. // Send close with message data
  302. procedure Close(aData : TBytes = Nil); overload;
  303. procedure Close(aMessage : UTF8String); overload;
  304. procedure Close(aMessage : UTF8String; aReason: word); overload;
  305. // Check incoming message
  306. function CheckIncoming(aTimeout: Integer; DoRead : Boolean = True): TIncomingResult;
  307. // read & process incoming message. Return nil if connection was close.
  308. function ReadMessage: Boolean;
  309. // Disconnect
  310. Procedure Disconnect;
  311. // Descendents can override this to provide custom frames
  312. Function FrameClass : TWSFrameClass; virtual;
  313. // Send raw frame. No checking is done !
  314. procedure Send(aFrame : TWSFrame); virtual;
  315. // Send message
  316. procedure Send(const AMessage: UTF8string);
  317. // Send binary data
  318. procedure Send(const ABytes: TBytes);
  319. // Send control frame. ftPing,ftPong,ftClose
  320. procedure Send(aFrameType: TFrameType; aData : TBytes = Nil);
  321. // Disconnect when status is set to csClosed;
  322. Property AutoDisconnect : Boolean Read FAutoDisconnect Write FAutoDisconnect;
  323. // Close frame handling
  324. Property CloseState : TCloseState Read FCloseState;
  325. // Connection ID, allocated during create
  326. Property ConnectionID : String Read FConnectionID;
  327. // If set to true, the owner data is freed when the connection is freed.
  328. Property FreeUserData : Boolean Read FFreeUserData Write FFreeUserData;
  329. // Request headers during handshake
  330. property HandshakeRequest: TWSHandShakeRequest read FHandshakeRequest;
  331. // Has handshake been completed ?
  332. property HandshakeCompleted: Boolean read GetHandshakeCompleted;
  333. // Options passed by server
  334. Property Options : TWSOptions Read FOptions;
  335. // Mask to use when sending frames. Set to nonzero value to send masked frames.
  336. Property OutgoingFrameMask : Integer Read FOutgoingFrameMask Write FOutgoingFrameMask;
  337. // Peer IP address
  338. property PeerIP: string read GetPeerIP;
  339. // Peer IP port
  340. property PeerPort: word read GetPeerPort;
  341. // Transport in use by this connection
  342. property Transport: IWSTransport read GetTransport;
  343. // User data to associate with this connection.
  344. Property UserData : TObject Read FUserData Write FUserData;
  345. // Socket version to check for
  346. Property WebSocketVersion : Integer Read FWebSocketVersion Write FWebSocketVersion;
  347. // Called when text/binary data was received
  348. property OnMessageReceived: TWSMessageEvent read FOnMessageReceived write FOnMessageReceived;
  349. // Called when Ping, Pong, Close control messages come in.
  350. property OnControl: TWSControlEvent read FOnControl write FOnControl;
  351. // Called when disconnect is called.
  352. property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
  353. end;
  354. { TWSClientTransport }
  355. TWSClientTransport = Class(TWSTransport)
  356. end;
  357. { TWSClientConnection }
  358. TWSClientConnection = Class(TWSConnection)
  359. private
  360. FTransport : TWSClientTransport;
  361. FHandshakeResponse: TWSHandShakeResponse;
  362. Protected
  363. function GetTransport : IWSTransport ; override;
  364. public
  365. Constructor Create(aOwner: TComponent; aTransport : TWSClientTransport; aOptions : TWSOptions); reintroduce; overload;
  366. Destructor Destroy; override;
  367. //
  368. function GetHandshakeCompleted: Boolean; override;
  369. // Owned by connection
  370. Property ClientTransport : TWSClientTransport Read FTransport;
  371. //
  372. Property HandShakeResponse : TWSHandShakeResponse Read FHandshakeResponse Write FHandshakeResponse;
  373. End;
  374. { TWSServerTransport }
  375. TWSServerTransport = class(TWSTransport)
  376. end;
  377. { TWSServerConnection }
  378. TWSConnectionHandshakeEvent = function(aRequest : TWSHandShakeRequest; aResponse : TWSHandShakeResponse): boolean of object;
  379. TWSServerConnection = Class(TWSConnection)
  380. Private
  381. FExtraHeaders: TStrings;
  382. FHandshakeResponseSent: Boolean;
  383. FOnHandShake: TWSConnectionHandshakeEvent;
  384. FTransport : TWSServerTransport;
  385. Protected
  386. Procedure DoDisconnect; override;
  387. function GetTransport: IWSTransport; override;
  388. function DoPrepareHandshakeResponse(aRequest : TWSHandShakeRequest; aResponse : TWSHandShakeResponse): boolean; virtual;
  389. function GetHandshakeCompleted: Boolean; override;
  390. public
  391. // Transport is owned by connection
  392. constructor Create(aOwner : TComponent; aTransport : TWSServerTransport; aOptions : TWSOptions); overload;
  393. // disconnect
  394. destructor Destroy; override;
  395. // Do full circle.
  396. Procedure PerformHandshake; virtual;
  397. // Given a request, send response
  398. function DoHandshake(const aRequest : TWSHandShakeRequest): Boolean; virtual;
  399. // Has handshake been exchanged?
  400. property HandshakeResponseSent: Boolean read FHandshakeResponseSent;
  401. // Extra handshake headers
  402. Property ExtraHeaders : TStrings Read FExtraHeaders;
  403. // Owned by connection
  404. property ServerTransport : TWSServerTransport Read FTransport;
  405. // Called when exchanging handshake
  406. Property OnHandshake : TWSConnectionHandshakeEvent Read FOnHandShake write FOnHandshake;
  407. end;
  408. Type
  409. { TBytesHelper }
  410. TBytesHelper = Type helper for TBytes
  411. // No swapping of bytes
  412. Function ToDword(aOffset : Integer = 0) : DWORD;
  413. Function ToInt32(aOffset : Integer = 0) : LongInt;
  414. Function ToWord(aOffset : Integer = 0) : Word;
  415. Function ToQWord(aOffset : Integer = 0) : QWord;
  416. Procedure FromDword(const aData : DWORD; aOffset : Integer = 0);
  417. Procedure FromInt32(const aData : Longint; aOffset : Integer = 0);
  418. Procedure FromWord(const aData : Word; aOffset : Integer = 0);
  419. Procedure FromQWord(const aData : QWord; aOffset : Integer = 0);
  420. procedure Reverse(var Dest: TBytes; Offset: Integer; Size: Integer);
  421. Function Reverse(Offset: Integer; Size: Integer) : TBytes;
  422. Procedure Append(aData : TBytes);
  423. end;
  424. Resourcestring
  425. SErrNotSimpleOperation = 'Frame type %d is not a simple operation.';
  426. SErrCloseAlreadySent = 'Close message already sent, cannot send more data.';
  427. SErrHandshakeInComplete = 'Operation cannot be performed while the handshake is not completed';
  428. SErrConnectionActive = 'Operation cannot be performed while the websocket connection is active';
  429. SErrConnectionInActive = 'Operation cannot be performed while the websocket connection is not active';
  430. SErrServerActive = 'Operation cannot be performed while the websocket connection is active';
  431. SErrInvalidSizeFlag = 'Invalid size flag: %d';
  432. SErrInvalidFrameType = 'Invalid frame type flag: %d';
  433. SErrWriteReturnedError = 'Write operation returned error: (%d) %s';
  434. function DecodeBytesBase64(const s: string; Strict: boolean = false) : TBytes;
  435. function EncodeBytesBase64(const aBytes : TBytes) : String;
  436. implementation
  437. {$IFDEF FPC_DOTTEDUNITS}
  438. uses System.StrUtils, System.Hash.Sha1, System.Hash.Base64;
  439. {$ELSE FPC_DOTTEDUNITS}
  440. uses strutils, sha1, base64;
  441. {$ENDIF FPC_DOTTEDUNITS}
  442. { TFrameTypeHelper }
  443. function TFrameTypeHelper.GetAsFlag: Byte;
  444. Const
  445. Flags : Array[TFrameType] of byte = (FlagContinuation,FlagText,FlagBinary,FlagClose,FlagPing,FlagPong,FlagReserved);
  446. begin
  447. Result:=Flags[Self];
  448. end;
  449. procedure TFrameTypeHelper.SetAsFlag(AValue: Byte);
  450. begin
  451. case aValue of
  452. FlagContinuation : Self:=ftContinuation;
  453. FlagText : Self:=ftText;
  454. FlagBinary : Self:=ftBinary;
  455. FlagClose : Self:=ftClose;
  456. FlagPing : Self:=ftPing;
  457. FlagPong : Self:=ftPong;
  458. else
  459. Self:=ftFutureOpcodes;
  460. end;
  461. end;
  462. { TWSHandShakeResponse }
  463. constructor TWSHandShakeResponse.Create(const aResource: string; const aExtraHeaders: TStrings);
  464. begin
  465. inherited Create(aResource, aExtraHeaders);
  466. HTTPVersion:='1.1';
  467. StatusCode:=101;
  468. StatusText:='Switching Protocols';
  469. end;
  470. procedure TWSHandShakeResponse.ToStrings(aHandShake: TWSHandshakeRequest; aResponse: TStrings; AddStatusLine: Boolean);
  471. Function CalcKey : String;
  472. Var
  473. B : TBytes;
  474. {%H-}hash : TSHA1Digest;
  475. K : string;
  476. begin
  477. // respond key
  478. b:=[];
  479. k:= Trim(aHandshake.Key) + SSecWebSocketGUID;
  480. hash:={$IFDEF FPC_DOTTEDUNITS}System.Hash.{$ENDIF}sha1.SHA1String(k);
  481. SetLength(B,SizeOf(hash));
  482. Move(Hash,B[0],Length(B));
  483. Result:=EncodeBytesBase64(B);
  484. end;
  485. begin
  486. // Fill needed headers
  487. Upgrade:='websocket';
  488. Connection:='Upgrade';
  489. // Chrome doesn't like it if you send an empty protocol header.
  490. if (Protocol='') and (aHandshake.Protocol<>'') then
  491. Protocol:=aHandshake.Protocol;
  492. if Version='' then
  493. Version:=IntToStr(DefaultWebSocketVersion);
  494. if Accept='' then
  495. Accept:=CalcKey;
  496. if AddStatusLine then
  497. aResponse.Add('HTTP/%s %d %s',[HTTPVersion,StatusCode,StatusText]);
  498. aResponse.AddStrings(RawHeaders);
  499. end;
  500. { TWSTransport }
  501. function TWSTransport.GetSocket: TSocketStream;
  502. begin
  503. Result:=FHelper.Socket;
  504. end;
  505. constructor TWSTransport.Create(aStream : TSocketStream);
  506. begin
  507. FStream:=aStream;
  508. FHelper:=TWSSocketHelper.Create(FStream);
  509. end;
  510. destructor TWSTransport.Destroy;
  511. begin
  512. FreeAndNil(FHelper);
  513. FreeAndNil(FStream);
  514. inherited Destroy;
  515. end;
  516. procedure TWSTransport.CloseSocket;
  517. begin
  518. if SocketClosed then exit;
  519. FSocketClosed:=true;
  520. {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.CloseSocket(FStream.Handle);
  521. end;
  522. { TWSTransport }
  523. constructor TWSSocketHelper.Create(aSocket: TSocketStream);
  524. begin
  525. FSocket:=aSocket;
  526. {$if defined(FreeBSD) or defined(Linux)}
  527. FSocket.ReadFlags:=MSG_NOSIGNAL;
  528. FSocket.WriteFlags:=MSG_NOSIGNAL;
  529. {$endif}
  530. end;
  531. function TWSSocketHelper.CanRead(aTimeOut: Integer): Boolean;
  532. begin
  533. Result:=FSocket.CanRead(aTimeout);
  534. end;
  535. function TWSSocketHelper.PeerIP: string;
  536. Function SocketAddrToString(ASocketAddr: TSockAddr): String;
  537. begin
  538. if ASocketAddr.sa_family = AF_INET then
  539. Result := NetAddrToStr(ASocketAddr.sin_addr)
  540. else // no ipv6 support yet
  541. Result := '';
  542. end;
  543. begin
  544. Result:= SocketAddrToString(FSocket.RemoteAddress);
  545. end;
  546. function TWSSocketHelper.PeerPort: word;
  547. Function SocketAddrToPort(ASocketAddr: TSockAddr): word;
  548. begin
  549. if ASocketAddr.sa_family = AF_INET then
  550. Result := ASocketAddr.sin_port
  551. else // no ipv6 support yet
  552. Result := 0;
  553. end;
  554. begin
  555. Result:=SocketAddrToPort(FSocket.RemoteAddress);
  556. end;
  557. function TWSSocketHelper.ReadLn: String;
  558. Var
  559. C : Byte;
  560. aSize : integer;
  561. begin
  562. // Preset
  563. Result:='';
  564. SetLength(Result,255);
  565. aSize:=0;
  566. C:=0;
  567. While (FSocket.Read(C,1)=1) and (C<>10) do
  568. begin
  569. Inc(aSize);
  570. if aSize>Length(Result) then
  571. SetLength(Result,Length(Result)+255);
  572. Result[aSize]:=AnsiChar(C);
  573. end;
  574. if (aSize>0) and (Result[aSize]=#13) then
  575. Dec(aSize);
  576. SetLength(Result,aSize);
  577. end;
  578. function TWSSocketHelper.ReadBytes(var aBytes: TBytes; aCount: Integer): Integer;
  579. var
  580. buf: TBytes;
  581. aPos, toRead: QWord;
  582. begin
  583. if aCount=0 then exit(0);
  584. aPos := 0;
  585. SetLength(aBytes, aCount);
  586. repeat
  587. SetLength(buf{%H-}, aCount);
  588. Result := FSocket.Read(buf[0], aCount - aPos);
  589. if Result <= 0 then
  590. break;
  591. SetLength(buf, Result);
  592. Move(buf[0], aBytes[aPos], Result);
  593. Inc(aPos, Result);
  594. ToRead := aCount - aPos;
  595. Result := aCount;
  596. until toRead <= 0;
  597. end;
  598. procedure TWSSocketHelper.ReadBuffer(aBytes: TBytes);
  599. begin
  600. if Length(ABytes)=0 then exit;
  601. FSocket.ReadBuffer(aBytes[0],Length(ABytes));
  602. end;
  603. function TWSSocketHelper.WriteBytes(aBytes: TBytes; aCount: Integer): Integer;
  604. begin
  605. if aCount=0 then exit(0);
  606. Result:=FSocket.Write(aBytes[0],aCount);
  607. end;
  608. procedure TWSSocketHelper.WriteBuffer(aBytes: TBytes);
  609. begin
  610. if Length(aBytes)=0 then exit;
  611. FSocket.WriteBuffer(aBytes[0],Length(aBytes));
  612. end;
  613. { TWSMessage }
  614. function TWSMessage.GetAsString: UTF8String;
  615. begin
  616. Result:=UTF8String(TEncoding.UTF8.GetString(Payload));
  617. end;
  618. function TWSMessage.GetAsUnicodeString: UnicodeString;
  619. begin
  620. Result:=UTF8Decode(asUTF8String);
  621. end;
  622. { TBytesHelper }
  623. function TBytesHelper.Reverse(Offset: Integer; Size: Integer): TBytes;
  624. begin
  625. Result:=[];
  626. Reverse(Result,Offset,Size);
  627. end;
  628. procedure TBytesHelper.Append(aData: TBytes);
  629. Var
  630. sLen,dLen : SizeInt;
  631. begin
  632. sLen:=Length(Self);
  633. dLen:=Length(aData);
  634. if dLen>0 then
  635. begin
  636. SetLength(Self,dLen+sLen);
  637. Move(aData[0],Self[sLen],dLen);
  638. end;
  639. end;
  640. procedure TBytesHelper.Reverse(var Dest: TBytes; Offset: Integer; Size: Integer);
  641. var
  642. I: Integer;
  643. begin
  644. SetLength(dest, Size);
  645. for I := 0 to Size - 1 do
  646. Dest[Size-1-I]:=Self[Offset+I];
  647. end;
  648. function TBytesHelper.ToInt32(aOffset: Integer = 0): LongInt;
  649. begin
  650. Result:=0;
  651. Move(Self[aOffSet],Result,SizeOf(LongInt));
  652. end;
  653. function TBytesHelper.ToDword(aOffset: Integer): DWORD;
  654. begin
  655. Result:=0;
  656. Move(Self[aOffSet],Result,SizeOf(DWORD));
  657. end;
  658. function TBytesHelper.ToWord(aOffset: Integer): Word;
  659. begin
  660. Result:=0;
  661. Move(Self[aOffSet],Result,SizeOf(Word));
  662. end;
  663. function TBytesHelper.ToQWord(aOffset: Integer): QWord;
  664. begin
  665. Result:=0;
  666. Move(Self[aOffSet],Result,SizeOf(QWord));
  667. end;
  668. procedure TBytesHelper.FromDword(const aData: DWORD; aOffset: Integer);
  669. begin
  670. Move(aData, Self[aOffSet],SizeOf(DWORD));
  671. end;
  672. procedure TBytesHelper.FromInt32(const aData: Longint; aOffset: Integer);
  673. begin
  674. Move(aData, Self[aOffSet],SizeOf(Longint));
  675. end;
  676. procedure TBytesHelper.FromWord(const aData: Word; aOffset: Integer = 0);
  677. begin
  678. Move(aData, Self[aOffSet],SizeOf(Word));
  679. end;
  680. procedure TBytesHelper.FromQWord(const aData: QWord; aOffset: Integer);
  681. begin
  682. Move(aData, Self[aOffSet],SizeOf(QWord));
  683. end;
  684. Function HToNx(Host: QWord) : QWord;
  685. begin
  686. {$ifdef FPC_BIG_ENDIAN}
  687. htonx:=host;
  688. {$else}
  689. htonx:=SwapEndian(host);
  690. {$endif}
  691. end;
  692. Function NToHx(Net: QWord) : QWord;
  693. begin
  694. {$ifdef FPC_BIG_ENDIAN}
  695. ntohx:=Net;
  696. {$else}
  697. ntohx:=SwapEndian(Net);
  698. {$endif}
  699. end;
  700. function EncodeBytesBase64(const aBytes : TBytes) : String;
  701. var
  702. OutStream : TStringStream;
  703. Encoder : TBase64EncodingStream;
  704. begin
  705. if Length(aBytes)=0 then
  706. Exit('');
  707. Encoder:=Nil;
  708. OutStream:=TStringStream.Create('');
  709. try
  710. Encoder:=TBase64EncodingStream.Create(OutStream);
  711. if Length(aBytes)>0 then
  712. Encoder.WriteBuffer(aBytes[0],Length(aBytes));
  713. Encoder.Flush;
  714. Result:=OutStream.DataString;
  715. finally
  716. Encoder.Free;
  717. OutStream.free;
  718. end;
  719. end;
  720. function DecodeBytesBase64(const s: string; Strict: boolean = false) : TBytes;
  721. Const
  722. StrictModes : Array[Boolean] of TBase64DecodingMode = (bdmMime,bdmStrict);
  723. var
  724. missing : Integer;
  725. SD : String;
  726. Instream,
  727. Outstream : TBytesStream;
  728. Decoder : TBase64DecodingStream;
  729. begin
  730. Result:=[];
  731. if Length(s)=0 then
  732. Exit;
  733. SD:=S;
  734. Missing:=Length(Sd) mod 4;
  735. if Missing>0 then
  736. SD:=SD+StringOfChar('=',Missing);
  737. Outstream:=Nil;
  738. Decoder:=Nil;
  739. Instream:=TStringStream.Create(SD);
  740. try
  741. Outstream:=TBytesStream.Create(Nil);
  742. Decoder:=TBase64DecodingStream.Create(Instream,StrictModes[Strict]);
  743. Outstream.CopyFrom(Decoder,Decoder.Size);
  744. Result:=Outstream.Bytes;
  745. finally
  746. Decoder.Free;
  747. Outstream.Free;
  748. Instream.Free;
  749. end;
  750. end;
  751. { TWSFramePayload }
  752. procedure TWSFramePayload.ReadData(var Content: TBytes; aTransport: IWSTransport);
  753. Const
  754. MaxBufSize = 32*1024;
  755. Var
  756. Buf : TBytes;
  757. aPos,toRead : QWord;
  758. aCount, FailCnt : Longint;
  759. begin
  760. Buf:=[];
  761. ToRead:=DataLength;
  762. aPos:=0;
  763. FailCnt:=0;
  764. Repeat
  765. aCount:=ToRead;
  766. if aCount>MaxBufSize then
  767. aCount:=MaxBufSize;
  768. SetLength(Buf,aCount);
  769. aCount := aTransport.ReadBytes(Buf,aCount);
  770. if aCount>0 then
  771. begin
  772. Move(Buf[0],Content[aPos],aCount);
  773. Inc(aPos,aCount);
  774. ToRead:=DataLength-aPos;
  775. FailCnt:=0;
  776. end
  777. else
  778. begin
  779. sleep(1);
  780. inc(FailCnt);
  781. if FailCnt>100 then
  782. raise Exception.Create('20230316102741 TWSFramePayload.ReadData');
  783. end;
  784. Until (ToRead<=0);
  785. end;
  786. procedure TWSFramePayload.Read(buffer: TBytes; aTransport: IWSTransport);
  787. Var
  788. LenFlag : Byte;
  789. paylen16 : Word;
  790. content: TBytes;
  791. begin
  792. content:=[];
  793. Masked := ((buffer[1] and FlagMasked) <> 0);
  794. LenFlag := buffer[1] and FlagLengthMask;
  795. Case LenFlag of
  796. FlagTwoBytes:
  797. begin
  798. aTransport.ReadBytes(Buffer,2);
  799. Paylen16:=Buffer.ToWord(0);
  800. DataLength := ntohs(PayLen16);
  801. end;
  802. FlagEightBytes:
  803. begin
  804. aTransport.ReadBytes(Buffer,8);
  805. DataLength:=Buffer.ToQWord(0);
  806. DataLength := ntohx(DataLength); // MVC : Needs fixing
  807. end
  808. else
  809. DataLength:=lenFlag;
  810. end;
  811. if Masked then
  812. begin
  813. // In some times, not 4 bytes are returned
  814. aTransport.ReadBytes(Buffer,4);
  815. MaskKey:=buffer.ToDword(0);
  816. end;
  817. SetLength(content, DataLength);
  818. if (DataLength>0) then
  819. begin
  820. ReadData(Content,aTransport);
  821. if Masked then
  822. DoMask(Content, MaskKey);
  823. Data := content;
  824. end;
  825. end;
  826. { TWSFrame }
  827. constructor TWSFrame.Create(aType: TFrameType; aIsFinal: Boolean; APayload: TBytes; aMask: Integer=0);
  828. begin
  829. Create(aType,aIsFinal,aMask);
  830. FPayload.Data := APayload;
  831. if Assigned(aPayload) then
  832. FPayload.DataLength := Cardinal(Length(aPayload));
  833. end;
  834. constructor TWSFrame.Create(aType: TFrameType; aIsFinal : Boolean = True; aMask: Integer=0);
  835. begin
  836. FReason:=CLOSE_NORMAL_CLOSURE;
  837. FPayload:=Default(TWSFramePayload);
  838. FPayload.MaskKey:=aMask;
  839. FPayload.Masked:=aMask<>0;
  840. FFrameType := aType;
  841. FFinalFrame := AIsFinal;
  842. end;
  843. constructor TWSFrame.Create(const aMessage: UTF8String; aMask: Integer=0);
  844. Var
  845. Data : TBytes;
  846. begin
  847. Data:=TEncoding.UTF8.GetBytes(UnicodeString(AMessage));
  848. Create(ftText,True,Data,aMask);
  849. end;
  850. class function TWSFrame.CreateFromStream(aTransport : IWSTransport): TWSFrame;
  851. begin
  852. Result:=TWSFrame.Create;
  853. try
  854. if not Result.Read(aTransport) then
  855. FreeAndNil(Result);
  856. except
  857. FreeAndNil(Result);
  858. Raise;
  859. end;
  860. end;
  861. function TWSFrame.Read(aTransport: IWSTransport): boolean;
  862. Var
  863. Buffer : Tbytes;
  864. B1 : Byte;
  865. begin
  866. Result:=False;
  867. Buffer:=Default(TBytes);
  868. SetLength(Buffer,2);
  869. if aTransport.ReadBytes(Buffer,2)=0 then
  870. Exit;
  871. if Length(Buffer)<2 then
  872. Raise EWebSocket.Create('Could not read frame header');
  873. B1:=buffer[0];
  874. FFinalFrame:=(B1 and FlagFinalFrame) = FlagFinalFrame;
  875. FRSV:=(B1 and %01110000) shr 4;
  876. FFrameType.AsFlag:=(B1 and $F);
  877. FPayload.Read(Buffer,aTransport);
  878. FReason:=CLOSE_NORMAL_CLOSURE;
  879. if FFrameType=ftClose then
  880. if FPayload.DataLength = 1 then
  881. FReason:=CLOSE_PROTOCOL_ERROR
  882. else
  883. if FPayload.DataLength>1 then
  884. begin
  885. FReason:=SwapEndian(FPayload.Data.ToWord(0));
  886. FPayload.DataLength := FPayload.DataLength - 2;
  887. if FPayload.DataLength > 0 then
  888. move(FPayload.Data[2], FPayload.Data[0], FPayload.DataLength);
  889. SetLength(FPayload.Data, FPayload.DataLength);
  890. end;
  891. Result:=True;
  892. end;
  893. function TWSFrame.GetAsBytes: TBytes;
  894. var
  895. LenByte,firstByte: Byte;
  896. buffer, LengthBytes: TBytes;
  897. aOffSet, I : Integer;
  898. pLen16 : Word;
  899. pLen64 : QWord;
  900. begin
  901. Result:=Nil;
  902. firstByte := FrameType.AsFlag;
  903. if FinalFrame then
  904. firstByte := firstByte or FlagFinalFrame;
  905. if FPayload.DataLength < FlagTwoBytes then
  906. begin
  907. aOffSet:=2;
  908. LenByte := Byte(FPayload.DataLength);
  909. LengthBytes:=[];
  910. end
  911. else if Payload.DataLength < (1 shl 16) then
  912. begin
  913. aOffset:=4;
  914. LenByte := FlagTwoBytes;
  915. plen16:=Payload.DataLength;
  916. SetLength(LengthBytes, SizeOf(Word));
  917. LengthBytes.FromWord(HToNs(pLen16));
  918. end
  919. else
  920. begin
  921. aOffset:=10;
  922. LenByte:=FlagEightBytes;
  923. plen64:=Payload.DataLength;
  924. SetLength(LengthBytes, Sizeof(UInt64));
  925. LengthBytes.FromQWord(HToNx(Plen64));
  926. end;
  927. Buffer:=[];
  928. if FPayload.Masked then
  929. begin
  930. lenByte:=Lenbyte or FlagMasked;
  931. aoffSet:=aOffSet+4;
  932. end;
  933. SetLength(buffer,aOffset+Int64(FPayload.DataLength));
  934. buffer[0] := firstByte;
  935. buffer[1] := LenByte;
  936. for I := 0 to Length(LengthBytes)-1 do
  937. buffer[2 + I] := LengthBytes[I];
  938. if Payload.Masked then
  939. begin
  940. Buffer.FromInt32(Payload.MaskKey,aOffSet-4);
  941. TWSFramePayload.CopyMasked(Payload.Data,Buffer,Payload.MaskKey,aOffset);
  942. end
  943. else
  944. if Payload.DataLength > 0 then
  945. move(Payload.Data[0], buffer[aOffset], Payload.DataLength);
  946. Result := Buffer;
  947. end;
  948. class procedure TWSFramePayload.DoMask(var aData: TBytes; Key: DWORD);
  949. begin
  950. CopyMasked(aData,aData,Key,0)
  951. end;
  952. class procedure TWSFramePayload.CopyMasked(SrcData: TBytes; var DestData: TBytes; Key: DWORD; aOffset: Integer);
  953. var
  954. currentMaskIndex: Longint;
  955. byteKeys: TBytes;
  956. I: Longint;
  957. begin
  958. CurrentMaskIndex := 0;
  959. byteKeys:=[];
  960. SetLength(byteKeys, SizeOf(Key));
  961. ByteKeys.FromDword(Key);
  962. for I := 0 to Length(SrcData) - 1 do
  963. begin
  964. DestData[I+aOffset] := SrcData[I] XOR byteKeys[currentMaskIndex];
  965. currentMaskIndex := (currentMaskIndex + 1) mod 4;
  966. end;
  967. end;
  968. class function TWSFramePayload.CopyMasked(SrcData: TBytes; Key: DWORD): TBytes;
  969. begin
  970. Result:=[];
  971. SetLength(Result,Length(SrcData));
  972. CopyMasked(SrcData,Result,Key,0)
  973. end;
  974. { TWSRequest }
  975. function TWSHeaders.GetS(aIdx: Integer): String;
  976. begin
  977. Result:=GetH(WSHeaderNames[aIdx]);
  978. end;
  979. procedure TWSHeaders.SetS(AIndex: Integer; const AValue: string);
  980. begin
  981. SetH(WSHeaderNames[aIndex],aValue);
  982. end;
  983. function TWSHeaders.GetH(const aName: string): String;
  984. begin
  985. Result:=Trim(FRawHeaders.Values[aName]);
  986. end;
  987. Procedure TWSHeaders.SetH(const aName,aValue: string);
  988. begin
  989. FRawHeaders.Values[aName]:=' '+aValue;
  990. end;
  991. constructor TWSHeaders.Create(Const aResource : String; const AHeaderList: TStrings);
  992. var
  993. I : Integer;
  994. N,V : String;
  995. begin
  996. FResource:=aResource;
  997. FRawHeaders:=TStringList.Create;
  998. FRawHeaders.NameValueSeparator:=':';
  999. if Assigned(aHeaderList) then
  1000. for I:=0 to aHeaderList.Count-1 do
  1001. begin
  1002. aHeaderList.GetNameValue(I,N,V);
  1003. if (N<>'') and (V<>'') then
  1004. FRawHeaders.Add(N+': '+Trim(V));
  1005. end;
  1006. end;
  1007. destructor TWSHeaders.Destroy;
  1008. begin
  1009. FreeAndNil(FRawHeaders);
  1010. inherited;
  1011. end;
  1012. { TWSConnection }
  1013. procedure TWSConnection.Send(aFrameType : TFrameType; aData : TBytes = Nil);
  1014. Var
  1015. aFrame : TWSFrame;
  1016. begin
  1017. if not (aFrameType in [ftClose,ftPing,ftPong]) then
  1018. Raise EWebSocket.CreateFmt(SErrNotSimpleOperation,[Ord(aFrameType)]);
  1019. aFrame:=FrameClass.Create(aFrameType,True,aData, OutgoingFrameMask);
  1020. try
  1021. Send(aFrame);
  1022. finally
  1023. aFrame.Free;
  1024. end;
  1025. end;
  1026. procedure TWSConnection.SetHandShakeRequest(aRequest: TWSHandShakeRequest);
  1027. begin
  1028. FreeAndNil(FHandshakeRequest);
  1029. FHandShakeRequest:=aRequest;
  1030. end;
  1031. constructor TWSConnection.Create(aOwner : TComponent; aOptions: TWSOptions);
  1032. begin
  1033. FOwner:=aOwner;
  1034. Foptions:=aOptions;
  1035. FWebSocketVersion:=WebSocketVersion;
  1036. AllocateConnectionID;
  1037. end;
  1038. destructor TWSConnection.Destroy;
  1039. begin
  1040. FreeAndNil(FHandshakeRequest);
  1041. If FreeUserData then
  1042. FreeAndNil(FUserData);
  1043. inherited;
  1044. end;
  1045. class function TWSConnection.GetCloseData(aBytes: TBytes; out aReason: String): Word;
  1046. begin
  1047. Result:=0;
  1048. aReason:='';
  1049. if Length(aBytes)>1 then
  1050. Result:=NToHs(aBytes.ToWord(0));
  1051. if Length(aBytes)>2 then
  1052. aReason:=TEncoding.UTF8.GetAnsiString(aBytes,2,Length(aBytes)-2);
  1053. end;
  1054. function TWSConnection.GetPeerIP: String;
  1055. Var
  1056. S : IWSTransport;
  1057. begin
  1058. S:=Transport;
  1059. if Assigned(S) then
  1060. Result:=S.PeerIP
  1061. else
  1062. Result:=''
  1063. end;
  1064. function TWSConnection.GetPeerPort: word;
  1065. Var
  1066. S : IWSTransport;
  1067. begin
  1068. S:=Transport;
  1069. if Assigned(S) then
  1070. Result:=S.PeerPort
  1071. else
  1072. Result:=0
  1073. end;
  1074. procedure TWSConnection.AllocateConnectionID;
  1075. begin
  1076. if Assigned(IDAllocator) then
  1077. IDAllocator(FConnectionID);
  1078. if FConnectionID='' then
  1079. {$IFDEF CPU64}
  1080. FConnectionID:=IntToStr(InterlockedIncrement64(_ConnectionCount));
  1081. {$ELSE}
  1082. FConnectionID:=IntToStr(InterlockedIncrement(_ConnectionCount));
  1083. {$ENDIF}
  1084. end;
  1085. procedure TWSConnection.SetCloseState(aValue: TCloseState);
  1086. begin
  1087. {$IFDEF VerboseStopServer}
  1088. writeln('TWSConnection.SetCloseState Old=',FCloseState,' New=',aValue);
  1089. {$ENDIF}
  1090. FCloseState:=aValue;
  1091. if (FCloseState=csClosed) and AutoDisconnect then
  1092. Disconnect;
  1093. end;
  1094. function TWSConnection.ReadMessage: Boolean;
  1095. begin
  1096. Result:=DoReadMessage;
  1097. end;
  1098. procedure TWSConnection.DispatchEvent(aInitialType: TFrameType; aFrame: TWSFrame; aMessageContent: TBytes);
  1099. Var
  1100. msg: TWSMessage;
  1101. begin
  1102. Case aInitialType of
  1103. ftPing,
  1104. ftPong,
  1105. ftClose :
  1106. If Assigned(FOnControl) then
  1107. FOnControl(Self,aInitialType,aMessageContent);
  1108. ftBinary,
  1109. ftText :
  1110. begin
  1111. if Assigned(FOnMessageReceived) then
  1112. begin
  1113. Msg:=Default(TWSMessage);
  1114. Msg.IsText:=(aInitialType=ftText);
  1115. if aFrame.FrameType=ftBinary then
  1116. Msg.Sequences:=[fsFirst]
  1117. else
  1118. Msg.Sequences:=[fsContinuation];
  1119. if aFrame.FinalFrame then
  1120. Msg.Sequences:=Msg.Sequences+[fsLast];
  1121. Msg.PayLoad:=aMessageContent;
  1122. FOnMessageReceived(Self, Msg);
  1123. end;
  1124. end;
  1125. ftContinuation: ; // Cannot happen normally
  1126. end;
  1127. end;
  1128. function TWSConnection.HandleIncoming(aFrame: TWSFrame) : Boolean;
  1129. Procedure UpdateCloseState;
  1130. begin
  1131. {$IFDEF VerboseStopServer}
  1132. writeln('TWSConnection.HandleIncoming START ',ClassName,' ',HexStr(Ptruint(Self),16),' FCloseState=',FCloseState);
  1133. {$ENDIF}
  1134. if (FCloseState=csNone) then
  1135. FCloseState:=csReceived
  1136. else if (FCloseState=csSent) then
  1137. FCloseState:=csClosed;
  1138. {$IFDEF VerboseStopServer}
  1139. writeln('TWSConnection.HandleIncoming END ',ClassName,' ',HexStr(Ptruint(Self),16),' FCloseState=',FCloseState);
  1140. {$ENDIF}
  1141. end;
  1142. procedure ProtocolError(aCode: Word);
  1143. begin
  1144. Close('', aCode);
  1145. UpdateCloseState;
  1146. Result:=false;
  1147. end;
  1148. begin
  1149. Result:=true;
  1150. // check Reserved bits
  1151. if aFrame.Reserved<>0 then
  1152. begin
  1153. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1154. Exit;
  1155. end;
  1156. // check Reserved opcode
  1157. if aFrame.FrameType = ftFutureOpcodes then
  1158. begin
  1159. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1160. Exit;
  1161. end;
  1162. { If control frame it must be complete }
  1163. if (aFrame.FrameType in [ftPing,ftPong,ftClose])
  1164. and (not aFrame.FinalFrame) then
  1165. begin
  1166. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1167. Exit;
  1168. end;
  1169. //
  1170. // here we handle payload.
  1171. // if aFrame.FrameType in [ftBinary,ftText] then
  1172. // begin
  1173. // FInitialOpcode:=aFrame.FrameType;
  1174. // FMessageContent:=aFrame.Payload.Data;
  1175. // end;
  1176. // Special handling
  1177. Case aFrame.FrameType of
  1178. ftContinuation:
  1179. begin
  1180. if FInitialOpcode=ftContinuation then
  1181. begin
  1182. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1183. Exit;
  1184. end;
  1185. FMessageContent.Append(aFrame.Payload.Data);
  1186. if aFrame.FinalFrame then
  1187. begin
  1188. if FInitialOpcode = ftText then
  1189. if IsValidUTF8(FMessageContent) then
  1190. DispatchEvent(FInitialOpcode,aFrame,FMessageContent)
  1191. else
  1192. ProtocolError(CLOSE_INVALID_FRAME_PAYLOAD_DATA)
  1193. else
  1194. DispatchEvent(FInitialOpcode,aFrame,FMessageContent);
  1195. // reset initial opcode
  1196. FInitialOpcode:=ftContinuation;
  1197. end;
  1198. end;
  1199. ftPing:
  1200. begin
  1201. if aFrame.Payload.DataLength > 125 then
  1202. ProtocolError(CLOSE_PROTOCOL_ERROR)
  1203. else
  1204. if not (woPongExplicit in Options) then
  1205. begin
  1206. Send(ftPong,aFrame.Payload.Data);
  1207. DispatchEvent(ftPing,aFrame,aFrame.Payload.Data);
  1208. end;
  1209. end;
  1210. ftClose:
  1211. begin
  1212. // If our side sent the initial close, this is the reply, and we must disconnect (Result=false).
  1213. Result:=FCloseState=csNone;
  1214. if Result then
  1215. begin
  1216. if (aFrame.Payload.DataLength>123) then
  1217. begin
  1218. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1219. exit;
  1220. end;
  1221. if not (woCloseExplicit in Options) then
  1222. begin
  1223. if (aFrame.Reason<CLOSE_NORMAL_CLOSURE) or
  1224. (aFrame.Reason=CLOSE_RESERVER) or
  1225. (aFrame.Reason=CLOSE_NO_STATUS_RCVD) or
  1226. (aFrame.Reason=CLOSE_ABNORMAL_CLOSURE) or
  1227. ((aFrame.Reason>CLOSE_TLS_HANDSHAKE) and (aFrame.Reason<3000)) then
  1228. begin
  1229. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1230. exit;
  1231. end;
  1232. if IsValidUTF8(aFrame.Payload.Data) then
  1233. begin
  1234. DispatchEvent(ftClose,aFrame,aFrame.Payload.Data);
  1235. UpdateCloseState;
  1236. Close('', aFrame.Reason); // Will update state, so call after UpdateCloseState
  1237. Result:=False; // We can disconnect.
  1238. end
  1239. else
  1240. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1241. end
  1242. else
  1243. UpdateCloseState
  1244. end
  1245. else
  1246. UpdateCloseState;
  1247. end;
  1248. ftBinary,ftText:
  1249. begin
  1250. if FInitialOpcode in [ftText, ftBinary] then
  1251. begin
  1252. ProtocolError(CLOSE_PROTOCOL_ERROR);
  1253. Exit;
  1254. end;
  1255. FInitialOpcode:=aFrame.FrameType;
  1256. FMessageContent:=aFrame.Payload.Data;
  1257. if aFrame.FinalFrame then
  1258. begin
  1259. if aFrame.FrameType = ftText then
  1260. if IsValidUTF8(aFrame.Payload.Data) then
  1261. DispatchEvent(FInitialOpcode,aFrame,aFrame.Payload.Data)
  1262. else
  1263. ProtocolError(CLOSE_INVALID_FRAME_PAYLOAD_DATA)
  1264. else
  1265. DispatchEvent(FInitialOpcode,aFrame,aFrame.Payload.Data);
  1266. FInitialOpcode:=ftContinuation;
  1267. end;
  1268. end;
  1269. else
  1270. ; // avoid Compiler warning
  1271. End;
  1272. end;
  1273. function TWSConnection.IsValidUTF8(aValue: TBytes): boolean;
  1274. var
  1275. i, len, n, j: integer;
  1276. c: ^byte;
  1277. begin
  1278. Result := true;
  1279. len := length(aValue);
  1280. if len = 0 then
  1281. exit;
  1282. Result := False;
  1283. i := 0;
  1284. c := @AValue[0];
  1285. while i < len do
  1286. begin
  1287. if (c^ <= $7f) then
  1288. n := 0
  1289. else if (c^ >= $c2) and (c^ <= $df) then
  1290. n := 1
  1291. else if (c^ = $e0) then
  1292. n := 2
  1293. else if (c^ >= $e1) and (c^ <= $ec) then
  1294. n := 2
  1295. else if (c^ = $ed) then
  1296. n := 2
  1297. else if (c^ >= $ee) and (c^ <= $ef) then
  1298. n := 2
  1299. else if (c^ = $f0) then
  1300. n := 3
  1301. else if (c^ >= $f1) and (c^ <= $f3) then
  1302. n := 3
  1303. else if (c^ = $f4) then
  1304. n := 3
  1305. else
  1306. exit;
  1307. j := 0;
  1308. Inc(i);
  1309. while j < n do
  1310. begin
  1311. if i >= len then
  1312. exit;
  1313. case c^ of
  1314. $c2..$df, $e1..$ec, $ee..$ef, $f1..$f3:
  1315. if not (((c + 1)^ >= $80) and ((c + 1)^ <= $bf)) then
  1316. exit;
  1317. $e0:
  1318. if not (((c + 1)^ >= $a0) and ((c + 1)^ <= $bf)) then
  1319. exit;
  1320. $ed:
  1321. if not (((c + 1)^ >= $80) and ((c + 1)^ <= $9f)) then
  1322. exit;
  1323. $f0:
  1324. if not (((c + 1)^ >= $90) and ((c + 1)^ <= $bf)) then
  1325. exit;
  1326. $f4:
  1327. if not (((c + 1)^ >= $80) and ((c + 1)^ <= $8f)) then
  1328. exit;
  1329. $80..$bf:
  1330. if not (((c + 1)^ >= $80) and ((c + 1)^ <= $bf)) then
  1331. exit;
  1332. end;
  1333. Inc(c);
  1334. Inc(i);
  1335. Inc(j);
  1336. end;
  1337. Inc(c);
  1338. end;
  1339. Result := True;
  1340. end;
  1341. function TWSConnection.FrameClass: TWSFrameClass;
  1342. begin
  1343. Result:=TWSFrame;
  1344. end;
  1345. procedure TWSConnection.Send(const AMessage: UTF8string);
  1346. var
  1347. aFrame: TWSFrame;
  1348. begin
  1349. aFrame:=FrameClass.Create(aMessage, OutgoingFrameMask);
  1350. try
  1351. Send(aFrame);
  1352. finally
  1353. aFrame.Free;
  1354. end;
  1355. end;
  1356. procedure TWSConnection.Send(const ABytes: TBytes);
  1357. var
  1358. aFrame: TWSFrame;
  1359. begin
  1360. aFrame:=FrameClass.Create(ftBinary,True,ABytes, OutgoingFrameMask);
  1361. try
  1362. Send(aFrame);
  1363. finally
  1364. aFrame.Free;
  1365. end;
  1366. end;
  1367. procedure TWSConnection.Close(aMessage: UTF8String);
  1368. begin
  1369. Close(aMessage, CLOSE_NORMAL_CLOSURE);
  1370. end;
  1371. procedure TWSConnection.Close(aMessage: UTF8String; aReason: word);
  1372. var
  1373. aData: TBytes;
  1374. aSize: Integer;
  1375. begin
  1376. aData := [];
  1377. // first two bytes is reason of close RFC 6455 section-5.5.1
  1378. aData := TEncoding.UTF8.GetAnsiBytes(aMessage);
  1379. aSize := Length(aData);
  1380. SetLength(aData, aSize + 2);
  1381. if aSize > 0 then
  1382. move(aData[0], aData[2], aSize);
  1383. aData[0] := (aReason and $FF00) shr 8;
  1384. aData[1] := aReason and $FF;
  1385. Close(aData);
  1386. end;
  1387. procedure TWSConnection.Disconnect;
  1388. begin
  1389. DoDisconnect;
  1390. if Assigned(FOnDisconnect) then
  1391. FOnDisconnect(Self);
  1392. end;
  1393. procedure TWSConnection.Close(aData: TBytes);
  1394. begin
  1395. Send(ftClose,aData);
  1396. end;
  1397. procedure TWSConnection.Send(aFrame: TWSFrame);
  1398. Var
  1399. Data : TBytes;
  1400. Res, Err : Integer;
  1401. ErrMsg : UTF8String;
  1402. begin
  1403. if FCloseState=csClosed then
  1404. Raise EWebSocket.Create(SErrCloseAlreadySent);
  1405. Data:=aFrame.AsBytes;
  1406. Res := Transport.WriteBytes(Data,Length(Data));
  1407. if Res < 0 then
  1408. begin
  1409. {$IFDEF VerboseStopServer}
  1410. writeln('TWSConnection.Send ',ClassName,' Connection=',HexStr(Ptruint(Self),16),' aFrame.FrameType=',aFrame.FrameType,' WriteBytes Failed, FCloseState=',FCloseState,' new=csClosed');
  1411. {$ENDIF}
  1412. FCloseState:=csClosed;
  1413. Err := GetLastOSError;
  1414. ErrMsg := Format(SErrWriteReturnedError, [Err, SysErrorMessage(Err)]);
  1415. if ErrMsg='' then
  1416. ErrMsg:=IntToStr(Err);
  1417. if woSendErrClosesConn in Options then
  1418. begin
  1419. {$IF SIZEOF(CHAR)=2}
  1420. SetLength(Data, 0);
  1421. Data.Append(TEncoding.UTF8.GetBytes(UnicodeString(ErrMsg)));
  1422. {$ELSE}
  1423. SetLength(Data, length(ErrMsg));
  1424. Move(ErrMsg[1],Data[0],length(Data));
  1425. {$ENDIF}
  1426. DispatchEvent(ftClose, nil, Data);
  1427. end
  1428. else
  1429. Raise EWebSocket.Create(ErrMsg);
  1430. end;
  1431. if (aFrame.FrameType=ftClose) then
  1432. begin
  1433. {$IFDEF VerboseStopServer}
  1434. writeln('TWSConnection.Send ',ClassName,' Connection=',HexStr(Ptruint(Self),16),' ftClose FCloseState=',FCloseState);
  1435. {$ENDIF}
  1436. if FCloseState=csNone then
  1437. FCloseState:=csSent
  1438. else if FCloseState=csReceived then
  1439. FCloseState:=csClosed;
  1440. end;
  1441. end;
  1442. function TWSConnection.DoReadMessage: Boolean;
  1443. Var
  1444. F : TWSFrame;
  1445. begin
  1446. Result:=False;
  1447. If not Transport.CanRead(0) then
  1448. Exit;
  1449. f:=FrameClass.CreateFromStream(Transport);
  1450. try
  1451. if Assigned(F) then
  1452. Result:=HandleIncoming(F)
  1453. finally
  1454. F.Free;
  1455. end;
  1456. end;
  1457. function TWSConnection.CheckIncoming(aTimeout: Integer; DoRead: Boolean = True): TIncomingResult;
  1458. begin
  1459. if not Transport.CanRead(aTimeOut) then
  1460. Result:=irNone
  1461. else if Not DoRead then
  1462. Result:=irWaiting
  1463. else if ReadMessage then
  1464. Result:=irOK
  1465. else
  1466. Result:=irClose;
  1467. end;
  1468. constructor TWSClientConnection.Create(aOwner: TComponent; aTransport: TWSClientTransport; aOptions : TWSOptions);
  1469. begin
  1470. Inherited Create(aOwner,aOptions);
  1471. FTransport:=aTransport;
  1472. end;
  1473. destructor TWSClientConnection.Destroy;
  1474. begin
  1475. FreeAndNil(FTransport);
  1476. inherited;
  1477. end;
  1478. function TWSClientConnection.GetHandshakeCompleted: Boolean;
  1479. begin
  1480. Result:=Assigned(FHandshakeResponse);
  1481. end;
  1482. function TWSClientConnection.GetTransport: IWSTransport;
  1483. begin
  1484. Result:=FTransport;
  1485. end;
  1486. { TWSHandShakeRequest }
  1487. Class Function TWSHandShakeRequest.GenerateKey : String;
  1488. Var
  1489. I : Integer;
  1490. B : TBytes;
  1491. begin
  1492. B:=[];
  1493. SetLength(B,16);
  1494. For I:=0 to 15 do
  1495. B[i]:=Random(256);
  1496. Result:=EncodeBytesBase64(B);
  1497. end;
  1498. constructor TWSHandShakeRequest.Create(const aResource: string; const aExtraHeaders: TStrings);
  1499. begin
  1500. Inherited Create(aResource,aExtraHeaders);
  1501. Version:=IntToStr(DefaultWebSocketVersion);
  1502. end;
  1503. procedure TWSHandShakeRequest.ToStrings(aHeaders: TStrings);
  1504. procedure Add(const AName, aValue, aDefault: String);
  1505. Var
  1506. V : String;
  1507. begin
  1508. V:=aValue;
  1509. if V='' then
  1510. V:=aDefault;
  1511. if V<>'' then
  1512. aHeaders.Add(aName+': '+V)
  1513. end;
  1514. Var
  1515. N,V : String;
  1516. I : Integer;
  1517. begin
  1518. aHeaders.Clear;
  1519. if Resource='' then
  1520. Resource:='/';
  1521. aHeaders.Add('GET ' + Resource + ' HTTP/1.1');
  1522. V:=Host;
  1523. if (V<>'') and (Port<>443) and (Port<>80) then
  1524. V:=V+':'+IntToStr(Port);
  1525. Add('Host',V,'');
  1526. Add('Upgrade',Upgrade,'websocket');
  1527. Add('Connection',Connection,'Upgrade');
  1528. Add('Origin',Origin,Host);
  1529. if Key='' then
  1530. Key:=GenerateKey;
  1531. Add('Sec-WebSocket-Key',Key,'');
  1532. Add('Sec-WebSocket-Protocol',Protocol,'');
  1533. Add('Sec-WebSocket-Version',Version,'');
  1534. For I:=0 to RawHeaders.Count-1 do
  1535. begin
  1536. RawHeaders.GetNameValue(I,N,V);
  1537. if (N<>'') and (V<>'') then
  1538. if (aHeaders.Values[N]='') then
  1539. Add(N,V,'')
  1540. end;
  1541. end;
  1542. { TWSServerConnection }
  1543. constructor TWSServerConnection.Create(aOwner : TComponent; aTransport : TWSServerTransport; aOptions : TWSOptions);
  1544. begin
  1545. Inherited Create(aOwner,aOptions);
  1546. FHandshakeResponseSent := False;
  1547. FTransport:=aTransport;
  1548. FExtraHeaders:=TStringList.Create;
  1549. FExtraHeaders.NameValueSeparator:=':';
  1550. end;
  1551. destructor TWSServerConnection.Destroy;
  1552. begin
  1553. if Assigned(FTransport) then
  1554. DisConnect;
  1555. FreeAndNil(FExtraHeaders);
  1556. inherited;
  1557. end;
  1558. procedure TWSServerConnection.PerformHandshake;
  1559. Var
  1560. Headers : TStrings;
  1561. aResource,Status,aLine : String;
  1562. HSR : TWSHandShakeRequest;
  1563. begin
  1564. Status:=Transport.ReadLn;
  1565. aResource:=ExtractWord(2,Status,[' ']);
  1566. HSR:=Nil;
  1567. Headers:=TStringList.Create;
  1568. try
  1569. Headers.NameValueSeparator:=':';
  1570. aLine:=Transport.ReadLn;
  1571. While aLine<>'' do
  1572. begin
  1573. Headers.Add(aLine);
  1574. aLine:=Transport.ReadLn;
  1575. end;
  1576. HSR:=TWSHandShakeRequest.Create(aResource,Headers);
  1577. FHandshakeResponseSent:=DoHandshake(HSR);
  1578. finally
  1579. HSR.Free;
  1580. Headers.Free;
  1581. end;
  1582. end;
  1583. function TWSServerConnection.GetHandshakeCompleted: Boolean;
  1584. begin
  1585. Result:=HandshakeResponseSent;
  1586. end;
  1587. procedure TWSServerConnection.DoDisconnect;
  1588. begin
  1589. if Assigned(FTransport) then
  1590. FTransport.CloseSocket;
  1591. FreeAndNil(FTransPort);
  1592. end;
  1593. function TWSServerConnection.GetTransport: IWSTransport;
  1594. begin
  1595. Result:=FTransport;
  1596. end;
  1597. function TWSServerConnection.DoPrepareHandshakeResponse(
  1598. aRequest: TWSHandShakeRequest; aResponse: TWSHandShakeResponse): boolean;
  1599. begin
  1600. If Assigned(OnHandshake) then
  1601. Result:=OnHandShake(aRequest,aResponse)
  1602. else
  1603. Result:=true;
  1604. end;
  1605. function TWSServerConnection.DoHandshake(const aRequest : TWSHandShakeRequest) : Boolean;
  1606. var
  1607. aLine,Reply : string;
  1608. aResp : TWSHandShakeResponse;
  1609. H : TStrings;
  1610. B : TBytes;
  1611. begin
  1612. Result:=False;
  1613. H:=Nil;
  1614. aResp:=TWSHandShakeResponse.Create('',FExtraHeaders);
  1615. try
  1616. try
  1617. DoPrepareHandshakeResponse(aRequest,aResp);
  1618. H:=TStringList.Create;
  1619. aResp.ToStrings(aRequest,H,True);
  1620. Reply:='';
  1621. For aLine in H do
  1622. Reply:=Reply+aLine+#13#10;
  1623. Reply:=Reply+#13#10;
  1624. B:=TEncoding.UTF8.GetAnsiBytes(Reply);
  1625. Transport.WriteBytes(B,Length(B));
  1626. Result:=True;
  1627. FHandshakeResponseSent:=True;
  1628. except
  1629. on E: Exception do
  1630. begin
  1631. // Close the connection if the handshake failed
  1632. Disconnect;
  1633. end;
  1634. end;
  1635. finally
  1636. H.Free;
  1637. aResp.Free;
  1638. end;
  1639. end;
  1640. end.