/// <summary> /// Are about to send a new message /// </summary> /// <param name="message">Message to send</param> /// <remarks> /// Can be used to prepare the next message. for instance serialize it etc. /// </remarks> /// <exception cref="NotSupportedException">Message is of a type that the encoder cannot handle.</exception> public void Prepare(object message) { if (message is IWebSocketMessage) { _message = (IWebSocketMessage)message; _message.Payload.Position = 0; _totalAmountToSend = (int)_message.Payload.Length; } else { try { _httpMessageEncoder.Prepare(message); var httpMessage = message as IHttpMessage; if (WebSocketUtils.IsWebSocketUpgrade(httpMessage)) { _handshake = httpMessage; } } catch (Exception e) { throw new InvalidOperationException("This encoder only supports messages deriving from 'HttpMessage' or 'WebSocketMessage'", e); } } }
/// <summary> /// Intercept http messages and look for websocket upgrade requests /// </summary> /// <param name="message">message from http decoder</param> private void OnHttpMessage(object message) { var httpMessage = message as IHttpMessage; // TODO: is there a better way to detect WebSocket upgrade? if (WebSocketUtils.IsWebSocketUpgrade(httpMessage)) { _handshake = httpMessage; _isWebSocket = true; } _messageReceived(message); }
/// <summary> /// Handles the upgrade /// </summary> /// <param name="source">Channel that we've received a request from</param> /// <param name="msg">Message received.</param> protected override void OnMessage(ITcpChannel source, object msg) { var httpMessage = msg as IHttpMessage; if (WebSocketUtils.IsWebSocketUpgrade(httpMessage)) { if (httpMessage is IHttpRequest) // server mode { var args = new WebSocketClientConnectEventArgs(source, (IHttpRequest)httpMessage); WebSocketClientConnect(this, args); if (args.MayConnect) { var webSocketKey = httpMessage.Headers["Sec-WebSocket-Key"]; // TODO: why not provide the response in the WebSocketClientConnectEventArgs event? var response = new WebSocketUpgradeResponse(webSocketKey); source.Send(response); WebSocketClientConnected(this, new WebSocketClientConnectedEventArgs(source, (IHttpRequest)httpMessage, response)); } else { var response = new HttpResponseBase(HttpStatusCode.NotImplemented, "Not Implemented", "HTTP/1.1"); if (args.Response != null) { response.Body = args.Response; } source.Send(response); } return; } if (httpMessage is IHttpResponse) // client mode { WebSocketClientConnected(this, new WebSocketClientConnectedEventArgs(source, null, (IHttpResponse)httpMessage)); } } var webSocketMessage = msg as IWebSocketMessage; if (webSocketMessage != null) { // standard message responses handled by listener switch (webSocketMessage.Opcode) { case WebSocketOpcode.Ping: source.Send(new WebSocketMessage(WebSocketOpcode.Pong, webSocketMessage.Payload)); return; case WebSocketOpcode.Close: source.Send(new WebSocketMessage(WebSocketOpcode.Close)); source.Close(); WebSocketClientDisconnected(this, new ClientDisconnectedEventArgs(source, new Exception("WebSocket closed"))); return; } _webSocketMessageReceived(source, webSocketMessage); return; } base.OnMessage(source, msg); }