/// <summary> /// Handles an incoming raw HTTP response. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> private void HandleIncomingResponse(ISockNetChannel channel, ref object obj) { if (!(obj is ChunkedBuffer)) { return; } ChunkedBuffer data = (ChunkedBuffer)obj; if (currentIncoming == null) { currentIncoming = new HttpResponse(channel.BufferPool); } if (currentIncoming.Parse(data.Stream, channel.IsActive)) { if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received HTTP Response: Command Line: [{0}], Body Size [{1}]", currentIncoming.CommandLine, currentIncoming.BodySize); } obj = currentIncoming; currentIncoming = null; } }
/// <summary> /// Invoked when the channel has sucessfully attached. /// </summary> /// <param name="channel"></param> /// <param name="error"></param> /// <param name="promise"></param> private void OnAttached(ISockNetChannel channel, Exception error, Promise <ISockNetChannel> promise) { promise.OnFulfilled = null; Pipe.HandleOpened(); State = RemoteSockNetChannelState.Connected; }
/// <summary> /// Installs a per channel module. /// </summary> /// <param name="channel"></param> public void Install(ISockNetChannel channel) { ISockNetChannelModule module = NewPerChannelModule(); if (channel.SetAttribute(ModuleName, module, false)) { module.Install(channel); } }
/// <summary> /// Handles incoming raw frames and translates them into WebSocketFrame(s) /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleIncomingFrames(ISockNetChannel channel, ref object data) { if (!(data is ChunkedBuffer)) { return; } ChunkedBuffer stream = (ChunkedBuffer)data; long startingPosition = stream.ReadPosition; try { WebSocketFrame frame = WebSocketFrame.ParseFrame(stream.Stream); if (combineContinuations) { if (frame.IsFinished) { UpdateContinuation(ref continuationFrame, frame); data = continuationFrame; continuationFrame = null; } else { UpdateContinuation(ref continuationFrame, frame); } } else { data = frame; } if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received WebSocket message. Size: {0}, Type: {1}, IsFinished: {2}", frame.Data.Length, Enum.GetName(typeof(WebSocketFrame.WebSocketFrameOperation), frame.Operation), frame.IsFinished); } } catch (EndOfStreamException) { // websocket frame isn't done stream.ReadPosition = startingPosition; } catch (ArgumentOutOfRangeException) { // websocket frame isn't done stream.ReadPosition = startingPosition; } catch (Exception e) { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Unable to parse web-socket request", e); channel.Close(); } }
/// <summary> /// Uninstalls a per channel module. /// </summary> /// <param name="channel"></param> public void Uninstall(ISockNetChannel channel) { object module; if (channel.TryGetAttribute(ModuleName, out module)) { ((ISockNetChannelModule)module).Uninstall(channel); channel.RemoveAttribute(ModuleName); } }
/// <summary> /// Uninstalls this module. /// </summary> /// <param name="channel"></param> public void Uninstall(ISockNetChannel channel) { channel.Pipe.RemoveIncoming <HttpRequest>(HandleHandshake); channel.Pipe.RemoveIncoming <object>(HandleIncomingFrames); channel.Pipe.RemoveOutgoing <object>(HandleOutgoingFrames); if (channel.HasModule(httpModule)) { channel.RemoveModule(httpModule); } }
/// <summary> /// Handles an incomming raw Gds message. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> public void HandleIncoming(ISockNetChannel channel, ref object obj) { if (!(obj is ChunkedBuffer)) { return; } ChunkedBuffer stream = (ChunkedBuffer)obj; long startingPosition = stream.ReadPosition; try { GdsFrame frame = GdsFrame.ParseFrame(stream.Stream, channel.BufferPool); if (combineChunks) { if (frame.IsComplete) { UpdateChunk(ref chunkedFrame, frame, channel); obj = chunkedFrame; chunkedFrame = null; } else { UpdateChunk(ref chunkedFrame, frame, channel); } } else { obj = frame; } if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received Gds message. Body Size: {0}, Type: {1}, IsComplete: {2}", frame.Body.AvailableBytesToRead, Enum.GetName(typeof(GdsFrame.GdsFrameType), frame.Type), frame.IsComplete); } } catch (EndOfStreamException) { // frame isn't done stream.ReadPosition = startingPosition; } catch (ArgumentOutOfRangeException) { // frame isn't done stream.ReadPosition = startingPosition; } catch (Exception e) { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Unable to parse Gds message", e); } }
/// <summary> /// Handles WebSocketFrame(s) and translates them into raw frames. /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleOutgoingFrames(ISockNetChannel channel, ref object data) { if (!(data is WebSocketFrame)) { return; } WebSocketFrame webSocketFrame = (WebSocketFrame)data; ChunkedBuffer buffer = new ChunkedBuffer(channel.BufferPool); webSocketFrame.Write(buffer.Stream); data = buffer; }
/// <summary> /// Clones this pipe and sets the given parent. /// </summary> /// <param name="newParent"></param> /// <param name="includeModules"></param> /// <returns></returns> public SockNetChannelPipe Clone(ISockNetChannel newParent, bool includeModules = true) { SockNetChannelPipe newPipe = new SockNetChannelPipe(newParent); lock (openedHandlers) { foreach (OnOpenedDelegate del in openedHandlers) { if (includeModules || !(del.Target is ISockNetChannelModule)) { newPipe.openedHandlers.AddLast(del); } } } lock (closedHandlers) { foreach (OnClosedDelegate del in closedHandlers) { if (includeModules || !(del.Target is ISockNetChannelModule)) { newPipe.closedHandlers.AddLast(del); } } } lock (incomingHandlers) { foreach (IDelegateReference del in incomingHandlers) { if (includeModules || !(del.Delegate.Target is ISockNetChannelModule)) { newPipe.incomingHandlers.AddLast(del); } } } lock (outgoingHandlers) { foreach (IDelegateReference del in outgoingHandlers) { if (includeModules || !(del.Delegate.Target is ISockNetChannelModule)) { newPipe.outgoingHandlers.AddLast(del); } } } return(newPipe); }
/// <summary> /// Handles an outgoing HttpRequest and converts it to a raw buffer. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> public void HandleOutgoing(ISockNetChannel channel, ref object obj) { if (!(obj is GdsFrame)) { return; } GdsFrame gdsFrame = (GdsFrame)obj; ChunkedBuffer buffer = new ChunkedBuffer(channel.BufferPool); gdsFrame.Write(buffer.Stream); gdsFrame.Dispose(); obj = buffer; }
/// <summary> /// Handles the WebSocket handshake. /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleHandshake(ISockNetChannel channel, ref HttpRequest request) { string connection = request.Header["Connection"]; string upgrade = request.Header["Upgrade"]; string securityKey = request.Header[WebSocketUtil.WebSocketKeyHeader]; if (connection != null && upgrade != null && securityKey != null && "websocket".Equals(upgrade.Trim().ToLower()) && "upgrade".Equals(connection.Trim().ToLower())) { string[] requestProtocols = request.Headers[WebSocketUtil.WebSocketProtocolHeader]; List <string> handledProtocols = new List <string>(); if (requestProtocols != null && protocolDelegate != null) { for (int i = 0; i < requestProtocols.Length; i++) { if (protocolDelegate(channel, requestProtocols[i])) { handledProtocols.Add(requestProtocols[i]); } } } HttpResponse response = new HttpResponse(channel.BufferPool) { Version = "HTTP/1.1", Code = "101", Reason = "Switching Protocols" }; response.Header["Upgrade"] = "websocket"; response.Header["Connection"] = "Upgrade"; response.Header[WebSocketUtil.WebSocketAcceptHeader] = WebSocketUtil.GenerateAccept(securityKey); response.Header[WebSocketUtil.WebSocketProtocolHeader] = string.Join(",", handledProtocols.ToArray()); channel.Send(response); channel.RemoveModule(httpModule); channel.Pipe.AddIncomingFirst <object>(HandleIncomingFrames); channel.Pipe.AddOutgoingLast <object>(HandleOutgoingFrames); } else { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Expecting upgrade request."); channel.Close(); } }
/// <summary> /// Invoked on channel connect. /// </summary> /// <param name="channel"></param> public void OnConnected(ISockNetChannel channel) { SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Sending WebSocket upgrade request."); channel.Pipe.AddIncomingLast <HttpResponse>(HandleHandshake); HttpRequest request = new HttpRequest(channel.BufferPool) { Action = "GET", Path = path, Version = "HTTP/1.1" }; request.Header["Host"] = hostname; request.Header["Upgrade"] = "websocket"; request.Header["Connection"] = "Upgrade"; request.Header[WebSocketUtil.WebSocketKeyHeader] = secKey; request.Header[WebSocketUtil.WebSocketVersionHeader] = "13"; channel.Send(request); }
/// <summary> /// Handles an outgoing HttpRequest and converts it to a raw buffer. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> private void HandleOutgoingRequest(ISockNetChannel channel, ref object obj) { if (!(obj is HttpRequest)) { return; } HttpRequest data = (HttpRequest)obj; if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Sending HTTP Request: Command Line: [{0}], Body Size [{1}]", data.CommandLine, data.BodySize); } ChunkedBuffer buffer = new ChunkedBuffer(channel.BufferPool); data.Write(buffer.Stream); data.Dispose(); obj = buffer; }
/// <summary> /// Handles the WebSocket handshake. /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleHandshake(ISockNetChannel channel, ref HttpResponse data) { if (expectedAccept.Equals(data.Header[WebSocketUtil.WebSocketAcceptHeader])) { SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Established Web-Socket connection."); channel.Pipe.RemoveIncoming <HttpResponse>(HandleHandshake); channel.Pipe.AddIncomingFirst <object>(HandleIncomingFrames); channel.Pipe.AddOutgoingLast <object>(HandleOutgoingFrames); channel.RemoveModule(httpModule); if (onWebSocketEstablished != null) { onWebSocketEstablished(channel); } } else { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Web-Socket handshake incomplete."); channel.Close(); } }
public void Install(ISockNetChannel channel) { channel.Pipe.AddIncomingFirst <object>(HandleIncoming); channel.Pipe.AddOutgoingLast <object>(HandleOutgoing); }
/// <summary> /// Updates the given chunked frame with a new frame. /// </summary> /// <param name="frame"></param> private static void UpdateChunk(ref GdsFrame chunkedFrame, GdsFrame frame, ISockNetChannel channel) { if (chunkedFrame == null) { chunkedFrame = frame; // set initial frame } else { if (frame.Type == GdsFrame.GdsFrameType.Ping || frame.Type == GdsFrame.GdsFrameType.Pong || frame.Type == GdsFrame.GdsFrameType.Close) { chunkedFrame = frame; } GdsFrame.GdsFrameType type = chunkedFrame.Type; ChunkedBuffer body = null; if (frame.Type == GdsFrame.GdsFrameType.BodyOnly || frame.Type == GdsFrame.GdsFrameType.Full) { if (type == GdsFrame.GdsFrameType.HeadersOnly) { type = GdsFrame.GdsFrameType.Full; } body = new ChunkedBuffer(channel.BufferPool); chunkedFrame.Body.DrainToStreamSync(body.Stream).Close(); frame.Body.DrainToStreamSync(body.Stream).Close(); } Dictionary <string, byte[]> headers = null; if (frame.Type == GdsFrame.GdsFrameType.HeadersOnly || frame.Type == GdsFrame.GdsFrameType.Full) { if (type == GdsFrame.GdsFrameType.BodyOnly) { type = GdsFrame.GdsFrameType.Full; } headers = new Dictionary <string, byte[]>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair <string, byte[]> kvp in chunkedFrame.Headers) { headers[kvp.Key] = kvp.Value; } foreach (KeyValuePair <string, byte[]> kvp in frame.Headers) { headers[kvp.Key] = kvp.Value; } } chunkedFrame.Dispose(); frame.Dispose(); chunkedFrame = GdsFrame.NewContentFrame(frame.StreamId, headers, false, body, frame.IsComplete); } }
/// <summary> /// Handles the WebSocket handshake. /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleHandshake(ISockNetChannel channel, ref HttpRequest request) { string connection = request.Header["Connection"]; string upgrade = request.Header["Upgrade"]; string securityKey = request.Header[WebSocketUtil.WebSocketKeyHeader]; if (connection != null && upgrade != null && securityKey != null && "websocket".Equals(upgrade.Trim().ToLower()) && "upgrade".Equals(connection.Trim().ToLower())) { string[] requestProtocols = request.Headers[WebSocketUtil.WebSocketProtocolHeader]; List<string> handledProtocols = new List<string>(); if (requestProtocols != null && protocolDelegate != null) { for (int i = 0; i < requestProtocols.Length; i++) { if (protocolDelegate(channel, requestProtocols[i])) { handledProtocols.Add(requestProtocols[i]); } } } HttpResponse response = new HttpResponse(channel.BufferPool) { Version = "HTTP/1.1", Code = "101", Reason = "Switching Protocols" }; response.Header["Upgrade"] = "websocket"; response.Header["Connection"] = "Upgrade"; response.Header[WebSocketUtil.WebSocketAcceptHeader] = WebSocketUtil.GenerateAccept(securityKey); response.Header[WebSocketUtil.WebSocketProtocolHeader] = string.Join(",", handledProtocols.ToArray()); channel.Send(response); channel.RemoveModule(httpModule); channel.Pipe.AddIncomingFirst<object>(HandleIncomingFrames); channel.Pipe.AddOutgoingLast<object>(HandleOutgoingFrames); } else { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Expecting upgrade request."); channel.Close(); } }
/// <summary> /// Invoked when there is outgoing data on the given channel. /// </summary> /// <param name="channel">the channel with the data</param> /// <param name="data">the data</param> public virtual void OnOutgoingData(ISockNetChannel channel, ref T data) { // noop }
/// <summary> /// Updates the given chunked frame with a new frame. /// </summary> /// <param name="frame"></param> private static void UpdateChunk(ref GdsFrame chunkedFrame, GdsFrame frame, ISockNetChannel channel) { if (chunkedFrame == null) { chunkedFrame = frame; // set initial frame } else { if (frame.Type == GdsFrame.GdsFrameType.Ping || frame.Type == GdsFrame.GdsFrameType.Pong || frame.Type == GdsFrame.GdsFrameType.Close) { chunkedFrame = frame; } GdsFrame.GdsFrameType type = chunkedFrame.Type; ChunkedBuffer body = null; if (frame.Type == GdsFrame.GdsFrameType.BodyOnly || frame.Type == GdsFrame.GdsFrameType.Full) { if (type == GdsFrame.GdsFrameType.HeadersOnly) { type = GdsFrame.GdsFrameType.Full; } body = new ChunkedBuffer(channel.BufferPool); chunkedFrame.Body.DrainToStreamSync(body.Stream).Close(); frame.Body.DrainToStreamSync(body.Stream).Close(); } Dictionary<string, byte[]> headers = null; if (frame.Type == GdsFrame.GdsFrameType.HeadersOnly || frame.Type == GdsFrame.GdsFrameType.Full) { if (type == GdsFrame.GdsFrameType.BodyOnly) { type = GdsFrame.GdsFrameType.Full; } headers = new Dictionary<string, byte[]>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, byte[]> kvp in chunkedFrame.Headers) { headers[kvp.Key] = kvp.Value; } foreach (KeyValuePair<string, byte[]> kvp in frame.Headers) { headers[kvp.Key] = kvp.Value; } } chunkedFrame.Dispose(); frame.Dispose(); chunkedFrame = GdsFrame.NewContentFrame(frame.StreamId, headers, false, body, frame.IsComplete); } }
/// <summary> /// Installs this module. /// </summary> /// <param name="channel"></param> public void Install(ISockNetChannel channel) { channel.AddModule(httpModule); channel.Pipe.AddOpenedLast(OnConnected); }
/// <summary> /// Uninstalls this module. /// </summary> /// <param name="channel"></param> public void Uninstall(ISockNetChannel channel) { channel.Pipe.RemoveIncoming<HttpResponse>(HandleHandshake); channel.Pipe.RemoveIncoming<object>(HandleIncomingFrames); channel.Pipe.RemoveOutgoing<object>(HandleOutgoingFrames); channel.Pipe.RemoveOpened(OnConnected); if (channel.HasModule(httpModule)) { channel.RemoveModule(httpModule); } }
/// <summary> /// Installs this module. /// </summary> /// <param name="channel"></param> public void Install(ISockNetChannel channel) { channel.AddModule(httpModule); channel.Pipe.AddIncomingLast <HttpRequest>(HandleHandshake); }
/// <summary> /// Invoked when the channel opens. /// </summary> /// <param name="channel">the channel that opened</param> public virtual void OnOpen(ISockNetChannel channel) { // noop }
/// <summary> /// Handles an outgoing HttpResponse and converts it into a raw buffer. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> private void HandleOutgoingResponse(ISockNetChannel channel, ref object obj) { if (!(obj is HttpResponse)) { return; } HttpResponse data = (HttpResponse)obj; if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Sending HTTP Response: Command Line: [{0}], Body Size [{1}]", data.CommandLine, data.BodySize); } ChunkedBuffer buffer = new ChunkedBuffer(channel.BufferPool); data.Write(buffer.Stream); data.Dispose(); obj = buffer; }
/// <summary> /// Invoked when the channel closes. /// </summary> /// <param name="channel">the channel that closed</param> public virtual void OnClose(ISockNetChannel channel) { // noop }
public void Uninstall(ISockNetChannel channel) { channel.Pipe.RemoveIncoming <object>(HandleIncoming); channel.Pipe.RemoveOutgoing <object>(HandleOutgoing); }
/// <summary> /// Installs this module. /// </summary> /// <param name="channel"></param> public void Install(ISockNetChannel channel) { channel.AddModule(httpModule); channel.Pipe.AddIncomingLast<HttpRequest>(HandleHandshake); }
public void Install(ISockNetChannel channel) { channel.Pipe.AddIncomingFirst<object>(HandleIncoming); channel.Pipe.AddOutgoingLast<object>(HandleOutgoing); }
/// <summary> /// Invoked on channel connect. /// </summary> /// <param name="channel"></param> public void OnConnected(ISockNetChannel channel) { SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Sending WebSocket upgrade request."); channel.Pipe.AddIncomingLast<HttpResponse>(HandleHandshake); HttpRequest request = new HttpRequest(channel.BufferPool) { Action = "GET", Path = path, Version = "HTTP/1.1" }; request.Header["Host"] = hostname; request.Header["Upgrade"] = "websocket"; request.Header["Connection"] = "Upgrade"; request.Header[WebSocketUtil.WebSocketKeyHeader] = secKey; request.Header[WebSocketUtil.WebSocketVersionHeader] = "13"; channel.Send(request); }
public void Uninstall(ISockNetChannel channel) { channel.Pipe.RemoveIncoming<object>(HandleIncoming); channel.Pipe.RemoveOutgoing<object>(HandleOutgoing); }
/// <summary> /// Handles the WebSocket handshake. /// </summary> /// <param name="channel"></param> /// <param name="request"></param> private void HandleHandshake(ISockNetChannel channel, ref HttpResponse data) { if (expectedAccept.Equals(data.Header[WebSocketUtil.WebSocketAcceptHeader])) { SockNetLogger.Log(SockNetLogger.LogLevel.INFO, this, "Established Web-Socket connection."); channel.Pipe.RemoveIncoming<HttpResponse>(HandleHandshake); channel.Pipe.AddIncomingFirst<object>(HandleIncomingFrames); channel.Pipe.AddOutgoingLast<object>(HandleOutgoingFrames); channel.RemoveModule(httpModule); if (onWebSocketEstablished != null) { onWebSocketEstablished(channel); } } else { SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Web-Socket handshake incomplete."); channel.Close(); } }
/// <summary> /// Creates a pipe with the given parent. /// </summary> /// <param name="parent"></param> public SockNetChannelPipe(ISockNetChannel parent) { this.parent = parent; }
/// <summary> /// Handles an incomming raw HTTP response. /// </summary> /// <param name="channel"></param> /// <param name="obj"></param> private void HandleIncomingRequest(ISockNetChannel channel, ref object obj) { if (!(obj is ChunkedBuffer)) { return; } ChunkedBuffer data = (ChunkedBuffer)obj; if (currentIncoming == null) { currentIncoming = new HttpRequest(channel.BufferPool); } if (currentIncoming.Parse(data.Stream, channel.IsActive)) { if (SockNetLogger.DebugEnabled) { SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received HTTP Request: Command Line: [{0}], Body Size [{1}]", currentIncoming.CommandLine, currentIncoming.BodySize); } obj = currentIncoming; currentIncoming = null; } }