async Task <RequestCommandAndStream> ReceiveRequestBodyOverControlAsync(ListenerCommand.RequestCommand requestCommand)
        {
            Stream requestStream = null;

            if (requestCommand.Body.Value)
            {
                // We need to buffer this body stream so we can let go of the listener control connection
                requestStream = new MemoryStream(BufferSize);
                using (var cts = new CancellationTokenSource(this.OperationTimeout))
                {
                    var buffer     = new ArraySegment <byte>(new byte[BufferSize]);
                    var readResult = await WebSocketUtility.ReadMessageAsync(this.controlWebSocket, buffer, requestStream, cts.Token).ConfigureAwait(false);

                    if (readResult.MessageType == WebSocketMessageType.Close)
                    {
                        throw RelayEventSource.Log.ThrowingException(new InvalidOperationException(SR.EntityClosedOrAborted), this);
                    }
                    else if (readResult.MessageType != WebSocketMessageType.Binary)
                    {
                        throw RelayEventSource.Log.ThrowingException(
                                  new ProtocolViolationException(SR.GetString(SR.InvalidType, WebSocketMessageType.Binary, readResult.MessageType)), this);
                    }

                    requestStream.Position = 0;
                }
            }

            return(new RequestCommandAndStream(requestCommand, requestStream));
        }
        void InvokeRequestHandler(RequestCommandAndStream requestAndStream)
        {
            ListenerCommand.RequestCommand requestCommand = requestAndStream.RequestCommand;
            Uri requestUri      = new Uri(this.listener.Address, requestCommand.RequestTarget);
            var listenerContext = new RelayedHttpListenerContext(
                this.listener,
                requestUri,
                requestCommand.Id,
                requestCommand.Method,
                requestCommand.RequestHeaders);

            listenerContext.Request.SetRemoteAddress(requestCommand.RemoteEndpoint);
            listenerContext.Response.StatusCode   = HttpStatusCode.OK;
            listenerContext.Response.OutputStream = new ResponseStream(this, listenerContext);

            RelayEventSource.Log.HybridHttpRequestReceived(listenerContext.TrackingContext, requestCommand.Method);

            Stream requestStream = requestAndStream.Stream;

            if (requestStream != null)
            {
                listenerContext.Request.HasEntityBody = true;
                listenerContext.Request.InputStream   = requestStream;
            }

            var requestHandler = this.listener.RequestHandler;

            if (requestHandler != null)
            {
                try
                {
                    RelayEventSource.Log.HybridHttpInvokingUserRequestHandler();
                    requestHandler(listenerContext);
                }
                catch (Exception userException) when(!Fx.IsFatal(userException))
                {
                    RelayEventSource.Log.HandledExceptionAsWarning(this, userException);
                    listenerContext.Response.StatusCode        = HttpStatusCode.InternalServerError;
                    listenerContext.Response.StatusDescription = this.TrackingContext.EnsureTrackableMessage(SR.RequestHandlerException);
                    listenerContext.Response.CloseAsync().Fork(this);
                    return;
                }
            }
            else
            {
                RelayEventSource.Log.HybridHttpConnectionMissingRequestHandler();
                listenerContext.Response.StatusCode        = HttpStatusCode.NotImplemented;
                listenerContext.Response.StatusDescription = this.TrackingContext.EnsureTrackableMessage(SR.RequestHandlerMissing);
                listenerContext.Response.CloseAsync().Fork(this);
            }
        }
        void InvokeRequestHandler(RequestCommandAndStream requestAndStream)
        {
            ListenerCommand.RequestCommand requestCommand = requestAndStream.RequestCommand;
            Uri requestUri      = new Uri(this.listener.Address, requestCommand.RequestTarget);
            var listenerContext = new RelayedHttpListenerContext(
                this.listener,
                requestUri,
                requestCommand.Id,
                requestCommand.Method,
                requestCommand.RequestHeaders);

            listenerContext.Request.SetRemoteAddress(requestCommand.RemoteEndpoint);
            listenerContext.Response.StatusCode   = HttpStatusCode.OK;
            listenerContext.Response.OutputStream = new ResponseStream(this, listenerContext);

            RelayEventSource.Log.HybridHttpRequestReceived(listenerContext.TrackingContext, requestCommand.Method);

            Stream requestStream = requestAndStream.Stream;

            if (requestStream != null)
            {
                listenerContext.Request.HasEntityBody = true;
                listenerContext.Request.InputStream   = requestStream;
            }

            var requestHandler = this.listener.RequestHandler;

            if (requestHandler != null)
            {
                try
                {
                    RelayEventSource.Log.HybridHttpInvokingUserRequestHandler();
                    requestHandler(listenerContext);
                }
                catch (Exception userException) when(!Fx.IsFatal(userException))
                {
                    RelayEventSource.Log.Warning(
                        listenerContext,
                        $"The Relayed Listener's custom RequestHandler threw an exception. {listenerContext.TrackingContext}, Exception: {userException}");
                    return;
                }
            }
            else
            {
                RelayEventSource.Log.HandledExceptionAsWarning(this, new InvalidOperationException("RequestHandler is not set."));
            }
        }
        public static async Task CreateAsync(HybridConnectionListener listener, ListenerCommand.RequestCommand requestCommand, WebSocket controlWebSocket)
        {
            var hybridHttpConnection = new HybridHttpConnection(listener, controlWebSocket, requestCommand.Address);

            // In this method we're holding up the listener's control connection.
            // Do only what we need to do (receive any request body from control channel) and then let this Task complete.
            bool requestOverControlConnection = requestCommand.Body.HasValue;
            var  requestAndStream             = new RequestCommandAndStream(requestCommand, null);

            if (requestOverControlConnection)
            {
                requestAndStream = await hybridHttpConnection.ReceiveRequestBodyOverControlAsync(requestCommand).ConfigureAwait(false);
            }

            // ProcessFirstRequestAsync runs without blocking the listener control connection:
            Task.Run(() => hybridHttpConnection.ProcessFirstRequestAsync(requestAndStream)).Fork(hybridHttpConnection);
        }
 public RequestCommandAndStream(ListenerCommand.RequestCommand requestCommand, Stream stream)
 {
     this.RequestCommand = requestCommand;
     this.Stream         = stream;
 }