/// <summary> /// Performs the opening handshake /// When call this method you <c>MUST NOT</c> retain the <see cref="IFullHttpRequest"/> which is passed in. /// </summary> /// <param name="channel">Channel</param> /// <param name="req">HTTP Request</param> /// <param name="responseHeaders">Extra headers to add to the handshake response or <code>null</code> if no extra headers should be added</param> /// <param name="completion">the <see cref="IPromise"/> to be notified when the opening handshake is done</param> public void Handshake(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders, IPromise completion) { #if DEBUG if (Logger.DebugEnabled) { Logger.WebSocketVersionServerHandshake(channel, _version); } #endif IFullHttpResponse response = NewHandshakeResponse(req, responseHeaders); IChannelPipeline p = channel.Pipeline; if (p.Get <HttpObjectAggregator>() is object) { _ = p.Remove <HttpObjectAggregator>(); } if (p.Get <HttpContentCompressor>() is object) { _ = p.Remove <HttpContentCompressor>(); } if (p.Get <CorsHandler>() is object) { _ = p.Remove <CorsHandler>(); } if (p.Get <HttpServerExpectContinueHandler>() is object) { _ = p.Remove <HttpServerExpectContinueHandler>(); } if (p.Get <HttpServerKeepAliveHandler>() is object) { _ = p.Remove <HttpServerKeepAliveHandler>(); } IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); string encoderName; if (ctx is null) { // this means the user use an HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx is null) { _ = completion.TrySetException(ThrowHelper.GetInvalidOperationException_NoHttpDecoderAndServerCodec()); return; } encoderName = ctx.Name; _ = p.AddBefore(encoderName, "wsencoder", NewWebSocketEncoder()); _ = p.AddBefore(encoderName, "wsdecoder", NewWebsocketDecoder()); } else { _ = p.Replace(ctx.Name, "wsdecoder", NewWebsocketDecoder()); encoderName = p.Context <HttpResponseEncoder>().Name; _ = p.AddBefore(encoderName, "wsencoder", NewWebSocketEncoder()); } _ = channel.WriteAndFlushAsync(response).ContinueWith(RemoveHandlerAfterWriteAction, (completion, p, encoderName), TaskContinuationOptions.ExecuteSynchronously); }
public void Handshake(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders, TaskCompletionSource completion) { if (Logger.DebugEnabled) { Logger.Debug("{} WebSocket version {} server handshake", channel, this.version); } IFullHttpResponse response = this.NewHandshakeResponse(req, responseHeaders); IChannelPipeline p = channel.Pipeline; if (p.Get <HttpObjectAggregator>() != null) { p.Remove <HttpObjectAggregator>(); } if (p.Get <HttpContentCompressor>() != null) { p.Remove <HttpContentCompressor>(); } IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); string encoderName; if (ctx == null) { // this means the user use a HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx == null) { completion.TrySetException(new InvalidOperationException("No HttpDecoder and no HttpServerCodec in the pipeline")); return; } p.AddBefore(ctx.Name, "wsdecoder", this.NewWebsocketDecoder()); p.AddBefore(ctx.Name, "wsencoder", this.NewWebSocketEncoder()); encoderName = ctx.Name; } else { p.Replace(ctx.Name, "wsdecoder", this.NewWebsocketDecoder()); encoderName = p.Context <HttpResponseEncoder>().Name; p.AddBefore(encoderName, "wsencoder", this.NewWebSocketEncoder()); } channel.WriteAndFlushAsync(response).ContinueWith(t => { if (t.Status == TaskStatus.RanToCompletion) { p.Remove(encoderName); completion.TryComplete(); } else { completion.TrySetException(t.Exception); } }); }
public sealed override void ChannelRegistered(IChannelHandlerContext context) { IChannelPipeline pipeline = context.Channel.Pipeline; bool success = false; try { this.InitChannel((T)context.Channel); pipeline.Remove(this); context.FireChannelRegistered(); success = true; } catch (Exception ex) { Logger.Warn("Failed to initialize a channel. Closing: " + context.Channel, ex); } finally { if (pipeline.Context(this) != null) { pipeline.Remove(this); } if (!success) { context.CloseAsync(); } } }
/// <summary> /// Performs the opening handshake /// When call this method you <c>MUST NOT</c> retain the <see cref="IHttpRequest"/> which is passed in. /// </summary> /// <param name="channel">Channel</param> /// <param name="req">HTTP Request</param> /// <param name="responseHeaders">Extra headers to add to the handshake response or <code>null</code> if no extra headers should be added</param> /// <returns></returns> public Task HandshakeAsync(IChannel channel, IHttpRequest req, HttpHeaders responseHeaders) { if (req is IFullHttpRequest request) { return(HandshakeAsync(channel, request, responseHeaders)); } if (Logger.DebugEnabled) { Logger.WebSocketVersionServerHandshake(channel, _version); } IChannelPipeline p = channel.Pipeline; IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); if (ctx is null) { // this means the user use an HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx is null) { return(ThrowHelper.ThrowInvalidOperationException_NoHttpDecoderAndServerCodec()); } } // Add aggregator and ensure we feed the HttpRequest so it is aggregated. A limit o 8192 should be more then // enough for the websockets handshake payload. // // TODO: Make handshake work without HttpObjectAggregator at all. string aggregatorName = "httpAggregator"; _ = p.AddAfter(ctx.Name, aggregatorName, new HttpObjectAggregator(8192)); var completion = channel.NewPromise(); _ = p.AddAfter(aggregatorName, "handshaker", new Handshaker(this, channel, responseHeaders, completion)); try { _ = ctx.FireChannelRead(ReferenceCountUtil.Retain(req)); } catch (Exception cause) { _ = completion.TrySetException(cause); } return(completion.Task); }
public Task HandshakeAsync(IChannel channel, IHttpRequest req, HttpHeaders responseHeaders) { if (req is IFullHttpRequest request) { return(this.HandshakeAsync(channel, request, responseHeaders)); } if (Logger.DebugEnabled) { Logger.Debug("{} WebSocket version {} server handshake", channel, this.version); } IChannelPipeline p = channel.Pipeline; IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); if (ctx == null) { // this means the user use a HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx == null) { return(TaskEx.FromException(new InvalidOperationException("No HttpDecoder and no HttpServerCodec in the pipeline"))); } } // Add aggregator and ensure we feed the HttpRequest so it is aggregated. A limit o 8192 should be more then // enough for the websockets handshake payload. // // TODO: Make handshake work without HttpObjectAggregator at all. string aggregatorName = "httpAggregator"; p.AddAfter(ctx.Name, aggregatorName, new HttpObjectAggregator(8192)); var completion = new TaskCompletionSource(); p.AddAfter(aggregatorName, "handshaker", new Handshaker(this, channel, responseHeaders, completion)); try { ctx.FireChannelRead(ReferenceCountUtil.Retain(req)); } catch (Exception cause) { completion.TrySetException(cause); } return(completion.Task); }
void Remove(IChannelHandlerContext ctx) { try { IChannelPipeline pipeline = ctx.Channel.Pipeline; if (pipeline.Context(this) != null) { pipeline.Remove(this); } } finally { initMap.TryRemove(ctx, out bool removed); } }