/// <summary> /// Create the web socket response headers. /// </summary> /// <param name="webSocketContext">The current web socket context.</param> private void CreateResponseHeaders(Nequeo.Net.WebSockets.WebSocketContext webSocketContext) { // If this is a WebSocket request then complete the handshaking. if (webSocketContext.WebSocketRequest.IsWebSocketRequest) { // Get the sec web socket accept key. byte[] webSocketKey = Nequeo.Cryptography.Hashcode.GetHashcodeSHA1Raw(webSocketContext.WebSocketRequest.SecWebSocketKey + Common.Resource.MagicGuid); string secWebSocketAccept = System.Convert.ToBase64String(webSocketKey); // Create the response and write the data back to the client. Nequeo.Net.WebSockets.WebSocketResponse response = webSocketContext.WebSocketResponse; response.SecWebSocketAccept = secWebSocketAccept; response.ContentLength = 0; response.Server = base.Name; // If protocols have been sent from the client // then assign the first one found. if (webSocketContext.WebSocketRequest.SecWebSocketProtocols != null && webSocketContext.WebSocketRequest.SecWebSocketProtocols.Length > 0) { response.SecWebSocketProtocol = webSocketContext.WebSocketRequest.SecWebSocketProtocols[0]; } // If extensions have been sent from the client // then assign the first one found. if (webSocketContext.WebSocketRequest.SecWebSocketExtensions != null && webSocketContext.WebSocketRequest.SecWebSocketExtensions.Length > 0) { response.SecWebSocketExtensions = webSocketContext.WebSocketRequest.SecWebSocketExtensions[0]; } // Indicate that handshaking is complete. webSocketContext.HandshakeComplete = true; } }
/// <summary> /// Create the web socket context. /// </summary> /// <param name="context">The current client context.</param> /// <returns>The web socket context.</returns> private Nequeo.Net.WebSockets.WebSocketContext CreateWebSocketContext(Nequeo.Net.Provider.Context context) { // Get the underlying web context. Nequeo.Net.WebContext webContext = CreateWebContext(context); // Create the new web socket context from the web context. Nequeo.Net.WebSockets.WebSocketContext webSocketContext = Nequeo.Net.WebSockets.WebSocketContext.CreateFrom(webContext); // Assign response and request data. webSocketContext.WebSocketResponse = new WebSocketResponse(); webSocketContext.WebSocketRequest = new WebSocketRequest(); webSocketContext.WebSocketResponse.Output = webContext.WebResponse.Output; webSocketContext.WebSocketRequest.Input = webContext.WebRequest.Input; // Return the request context. return(webSocketContext); }
/// <summary> /// Check to see if the request is a web socket. /// </summary> /// <param name="webSocketContext">The current web socket context.</param> private void CheckIfWebSocketRequest(Nequeo.Net.WebSockets.WebSocketContext webSocketContext) { // Make sure all handshaking has complete before continuing. if (!webSocketContext.HandshakeComplete) { // Get the request and response. Nequeo.Net.WebSockets.WebSocketRequest request = webSocketContext.WebSocketRequest; Nequeo.Net.WebSockets.WebSocketResponse response = webSocketContext.WebSocketResponse; Nequeo.Net.Http.Common.HttpStatusCode statusCode = null; // If not a web socket request. if (!webSocketContext.WebSocketRequest.IsWebSocketRequest) { // Get the bad request. statusCode = Nequeo.Net.Http.Utility.GetStatusCode(400); // Send bad request. response.Server = base.Name; response.ContentLength = 0; response.StatusCode = statusCode.Code; response.StatusDescription = statusCode.Description; response.ProtocolVersion = request.ProtocolVersion; } else { // Get the internal error. statusCode = Nequeo.Net.Http.Utility.GetStatusCode(500); // Send internal error. response.Server = base.Name; response.ContentLength = 0; response.StatusCode = statusCode.Code; response.StatusDescription = statusCode.Description; response.ProtocolVersion = request.ProtocolVersion; } // Not valid. throw new Exception("Not a valid WebSocket request."); } }
/// <summary> /// Create the web socket context from the web context. /// </summary> /// <param name="webContext">The web context to create from.</param> /// <returns>The web socket server context.</returns> public static WebSocketContext CreateFrom(Nequeo.Net.WebContext webContext) { Nequeo.Net.WebSockets.WebSocketContext webSocketContext = new Nequeo.Net.WebSockets.WebSocketContext(); webSocketContext.Context = webContext.Context; webSocketContext.IsStartOfConnection = webContext.IsStartOfConnection; webSocketContext.IsAuthenticated = webContext.IsAuthenticated; webSocketContext.IsSecureConnection = webContext.IsSecureConnection; webSocketContext.Name = webContext.Name; webSocketContext.NumberOfClients = webContext.NumberOfClients; webSocketContext.Port = webContext.Port; webSocketContext.RemoteEndPoint = webContext.RemoteEndPoint; webSocketContext.ServerEndPoint = webContext.ServerEndPoint; webSocketContext.ServiceName = webContext.ServiceName; webSocketContext.UniqueIdentifier = webContext.UniqueIdentifier; webSocketContext.ConnectionID = webContext.ConnectionID; webSocketContext.SessionID = webContext.SessionID; webSocketContext.User = webContext.User; webSocketContext.SocketState = webContext.SocketState; webSocketContext.IsAsyncMode = webContext.IsAsyncMode; webSocketContext.HandshakeComplete = false; return(webSocketContext); }
/// <summary> /// On received action handler. /// </summary> /// <param name="context">The current client context.</param> private void OnReceivedActionHandler(Nequeo.Net.Provider.Context context) { try { // Store data until all headers have been read. if (Nequeo.Net.Utility.IsParse2CRLF(context.Request.Input, context.RequestBufferStore, _maxHeaderBufferStore)) { // Create the web socket context and set the headers. Nequeo.Net.WebSockets.WebSocketContext webSocketContext = CreateWebSocketContext(context); // Get the headers from the stream and assign the request data. bool headersExist = Nequeo.Net.WebSockets.Utility.SetRequestHeaders(webSocketContext, base.HeaderTimeout, base.MaximumReadLength, context.RequestBufferStore); // Create the response headers. CreateResponseHeaders(webSocketContext); // Make sure all handshaking has complete before continuing. if (!webSocketContext.HandshakeComplete) { // Check to see if the request is a web socket. CheckIfWebSocketRequest(webSocketContext); } else { // Indicate that all web sockets after handshaking // is complete will run in async mode. webSocketContext.IsAsyncMode = true; // Create the central web socket context. CentralWebSocketContext centralWebSocketContext = new CentralWebSocketContext(webSocketContext); centralWebSocketContext.ConnectionID = webSocketContext.ConnectionID; centralWebSocketContext.Cookies = webSocketContext.WebSocketRequest.Cookies; centralWebSocketContext.Headers = webSocketContext.WebSocketRequest.Headers; centralWebSocketContext.IsAuthenticated = webSocketContext.IsAuthenticated; centralWebSocketContext.IsSecureConnection = webSocketContext.IsSecureConnection; centralWebSocketContext.SecWebSocketKey = webSocketContext.WebSocketRequest.SecWebSocketKey; centralWebSocketContext.SecWebSocketProtocols = webSocketContext.WebSocketRequest.SecWebSocketProtocols; centralWebSocketContext.SecWebSocketVersion = webSocketContext.WebSocketRequest.SecWebSocketVersion; centralWebSocketContext.SessionID = webSocketContext.SessionID; centralWebSocketContext.SocketState = webSocketContext.SocketState; centralWebSocketContext.UniqueIdentifier = webSocketContext.UniqueIdentifier; centralWebSocketContext.Url = webSocketContext.WebSocketRequest.Url; centralWebSocketContext.User = webSocketContext.User; // If the event has been assigned. if (OnWebSocketContext != null) { OnWebSocketContext(this, centralWebSocketContext); } // Write the response to the client. Nequeo.Net.WebSockets.WebSocketResponse response = webSocketContext.WebSocketResponse; response.WriteWebSocketHeaders(); // Create and assign the web socket. Nequeo.Net.WebSockets.WebSocket webSocket = new Nequeo.Net.WebSockets.WebSocket(centralWebSocketContext, response.ProtocolVersion); centralWebSocketContext.WebSocket = webSocket; // Save the web context state objects. SaveWebContext(context, webSocketContext); } } // If the maximum request buffer store has been reached then close the connection. if (context.RequestBufferStore.Length > _maxHeaderBufferStore) { throw new Exception("Maximum request buffer store has been reached."); } } catch (Exception) { // Close the connection and release all resources used for communication. context.Close(); } }
/// <summary> /// Set the request headers from the input stream within the current http context. /// </summary> /// <param name="webSocketContext">The current web socket context.</param> /// <param name="timeout">The maximum time in milliseconds to wait for the end of the header data; -1 wait Indefinitely.</param> /// <param name="maxReadLength">The maximun number of bytes to read before cancelling (must be greater then zero).</param> /// <param name="requestBufferStore">The request buffer store stream.</param> /// <exception cref="System.Exception"></exception> /// <returns>True if the headers have been found; else false.</returns> public static bool SetRequestHeaders(Nequeo.Net.WebSockets.WebSocketContext webSocketContext, long timeout = -1, int maxReadLength = 0, System.IO.Stream requestBufferStore = null) { // Header has not been found at this point. string requestMethod = ""; string protocolVersion = ""; byte[] rawData = null; List <NameValue> headers = null; // Web socket context is null. if (webSocketContext == null) { return(false); } // Web socket request context is null. if (webSocketContext.WebSocketRequest == null) { return(false); } // Web socket request context stream is null. if (webSocketContext.WebSocketRequest.Input == null) { return(false); } // If not using the buffer store. if (requestBufferStore == null) { // We need to wait until we get all the header // data then send the context to the server. headers = Nequeo.Net.Utility. ParseHeaders(webSocketContext.WebSocketRequest.Input, out requestMethod, ref rawData, timeout, maxReadLength); } else { // We need to wait until we get all the header // data then send the context to the server. headers = Nequeo.Net.Utility. ParseHeaders(webSocketContext.RequestBufferStore, out requestMethod, ref rawData, timeout, maxReadLength); } // If headers exist then all has been found. if (headers != null) { // Set all the request headers. webSocketContext.WebSocketRequest.ReadWebSocketHeaders(headers, requestMethod); protocolVersion = webSocketContext.WebSocketRequest.ProtocolVersion; webSocketContext.WebSocketRequest.HeadersFound = true; // If the client is using protocol version "HTTP/1.1" if (protocolVersion.ToUpper().Trim().Replace(" ", "").Contains("HTTP/1.1")) { // Do nothing. } // If the client is using protocol version "HTTP/2.0". if (protocolVersion.ToUpper().Trim().Replace(" ", "").Contains("HTTP/2")) { // Do nothing. } // Set the user principle if credentials // have been passed. if (webSocketContext.WebSocketRequest.Credentials != null) { // Add the credentials. Nequeo.Security.IdentityMember identity = new Nequeo.Security.IdentityMember( webSocketContext.WebSocketRequest.Credentials.UserName, webSocketContext.WebSocketRequest.Credentials.Password, webSocketContext.WebSocketRequest.Credentials.Domain); Nequeo.Security.AuthenticationType authType = Nequeo.Security.AuthenticationType.None; try { // Attempt to get the authentication type. authType = (Nequeo.Security.AuthenticationType) Enum.Parse(typeof(Nequeo.Security.AuthenticationType), webSocketContext.WebSocketRequest.AuthorizationType); } catch { } // Set the cuurent authentication schema. identity.AuthenticationSchemes = authType; // Create the principal. Nequeo.Security.PrincipalMember principal = new Nequeo.Security.PrincipalMember(identity, null); // Assign the principal webSocketContext.User = principal; } return(true); } else { return(false); } }