public async Task OnConnectedAsync(FramingConnection connection)
        {
            var  decoder = new ServerSingletonDecoder(ConnectionOrientedTransportDefaults.MaxViaSize, ConnectionOrientedTransportDefaults.MaxContentTypeSize, connection.Logger);
            bool success = false;

            try
            {
                ReadOnlySequence <byte> buffer;
                while (decoder.CurrentState != ServerSingletonDecoder.State.PreUpgradeStart)
                {
                    System.IO.Pipelines.ReadResult readResult = await connection.Input.ReadAsync();

                    buffer = readResult.Buffer;

                    while (buffer.Length > 0)
                    {
                        int bytesDecoded = decoder.Decode(buffer);
                        if (bytesDecoded > 0)
                        {
                            buffer = buffer.Slice(bytesDecoded);
                        }

                        if (decoder.CurrentState == ServerSingletonDecoder.State.PreUpgradeStart)
                        {
                            // We now know the Via address (which endpoint the client is connecting to).
                            // The connection now needs to be handled by the correct endpoint which can
                            // handle upgrades etc.
                            break; //exit loop
                        }
                    }

                    connection.Input.AdvanceTo(buffer.Start);
                }

                success = true;
            }
            catch (CommunicationException exception)
            {
                DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
            }
            catch (OperationCanceledException exception)
            {
                //if (TD.ReceiveTimeoutIsEnabled())
                //{
                //    TD.ReceiveTimeout(exception.Message);
                //}
                DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
            }
            catch (TimeoutException exception)
            {
                //if (TD.ReceiveTimeoutIsEnabled())
                //{
                //    TD.ReceiveTimeout(exception.Message);
                //}
                DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }
                if (!TransportExceptionHandler.HandleTransportExceptionHelper(e))
                {
                    throw;
                }
                // containment -- all exceptions abort the reader, no additional containment action necessary
            }
            finally
            {
                if (!success)
                {
                    // TODO: On .NET Framework, this Abort call via a long winding path of plumbing will trigger a new pending Accept
                    // as this connection establishment handshake has failed. Some back pressure mechanism needs to be implemented to
                    // stop extra incoming connection handshakes from being started. Maybe a semaphore which is async waited at initial
                    // incoming request and then released on completion of handshake or on an exception. It also closes the connection
                    // so that's all that's happening here for now. Returning and completing the task will cause the connection to be closed.
                    connection.Abort();
                }
            }

            if (success)
            {
                connection.FramingDecoder = decoder;
                await _next(connection);
            }
            // else:
            //   returning will close the connection if it hasn't already been.
        }
 protected override void OnAbort()
 {
     _tcs.TrySetResult(null);
     _connection.Abort();
 }
 void AbortReader()
 {
     _connection.Abort();
 }
예제 #4
0
        public async Task OnConnectedAsync(FramingConnection connection)
        {
            var  receiveTimeout = connection.ServiceDispatcher.Binding.ReceiveTimeout;
            var  timeoutHelper  = new TimeoutHelper(receiveTimeout);
            bool success        = false;

            try
            {
                var decoder = connection.FramingDecoder as ServerSingletonDecoder;
                Fx.Assert(decoder != null, "FramingDecoder must be non-null and an instance of ServerSessionDecoder");

                // first validate our content type
                //ValidateContentType(connection, decoder);
                UpgradeState upgradeState = UpgradeState.None;
                // next read any potential upgrades and finish consuming the preamble
                ReadOnlySequence <byte> buffer = ReadOnlySequence <byte> .Empty;
                while (true)
                {
                    if (buffer.Length == 0 && CanReadAndDecode(upgradeState))
                    {
                        var readResult = await connection.Input.ReadAsync();

                        buffer = readResult.Buffer;
                        if (readResult.IsCompleted)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException());
                        }
                    }

                    while (true)
                    {
                        if (CanReadAndDecode(upgradeState))
                        {
                            Fx.Assert(buffer.Length > 0, "There must be something in the buffer to decode");
                            int bytesDecoded = decoder.Decode(buffer);
                            if (bytesDecoded > 0)
                            {
                                buffer = buffer.Slice(bytesDecoded);
                                if (buffer.Length == 0)
                                {
                                    connection.Input.AdvanceTo(buffer.Start);
                                }
                            }
                        }

                        switch (decoder.CurrentState)
                        {
                        case ServerSingletonDecoder.State.UpgradeRequest:
                            switch (upgradeState)
                            {
                            case UpgradeState.None:
                                //change the state so that we don't read/decode until it is safe
                                ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                                break;

                            case UpgradeState.VerifyingUpgradeRequest:
                                if (connection.StreamUpgradeAcceptor == null)
                                {
                                    await connection.SendFaultAsync(FramingEncodingString.UpgradeInvalidFault, timeoutHelper.RemainingTime(), TransportDefaults.MaxDrainSize);

                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                              new ProtocolException(SR.Format(SR.UpgradeRequestToNonupgradableService, decoder.Upgrade)));
                                }

                                if (!connection.StreamUpgradeAcceptor.CanUpgrade(decoder.Upgrade))
                                {
                                    await connection.SendFaultAsync(FramingEncodingString.UpgradeInvalidFault, timeoutHelper.RemainingTime(), TransportDefaults.MaxDrainSize);

                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.Format(SR.UpgradeProtocolNotSupported, decoder.Upgrade)));
                                }

                                ChangeUpgradeState(ref upgradeState, UpgradeState.WritingUpgradeAck);
                                // accept upgrade
                                await connection.Output.WriteAsync(ServerSingletonEncoder.UpgradeResponseBytes, timeoutHelper.GetCancellationToken());

                                await connection.Output.FlushAsync(timeoutHelper.GetCancellationToken());

                                ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeAckSent);
                                break;

                            case UpgradeState.UpgradeAckSent:
                                // This state was used to capture any extra read bytes into PreReadConnection but we don't need to do that when using pipes.
                                // This extra state transition has been left here to maintain the same state transitions as on .NET Framework to make comparison easier.
                                ChangeUpgradeState(ref upgradeState, UpgradeState.BeginUpgrade);
                                break;

                            case UpgradeState.BeginUpgrade:
                                // Set input pipe so that the next read will return all the unconsumed bytes.
                                // If all bytes have already been consumed so the buffer has 0 length, AdvanceTo would throw
                                // as it's already been called.
                                if (buffer.Length > 0)
                                {
                                    connection.Input.AdvanceTo(buffer.Start);
                                }

                                buffer = ReadOnlySequence <byte> .Empty;
                                try
                                {
                                    await UpgradeConnectionAsync(connection);

                                    ChangeUpgradeState(ref upgradeState, UpgradeState.EndUpgrade);
                                }
                                catch (Exception exception)
                                {
                                    if (Fx.IsFatal(exception))
                                    {
                                        throw;
                                    }

                                    throw;
                                }
                                break;

                            case UpgradeState.EndUpgrade:
                                //Must be a different state here than UpgradeComplete so that we don't try to read from the connection
                                ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeComplete);
                                break;

                            case UpgradeState.UpgradeComplete:
                                //Client is doing more than one upgrade, reset the state
                                ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                                break;
                            }
                            break;

                        case ServerSingletonDecoder.State.Start:
                            SetupSecurityIfNecessary(connection);
                            if (upgradeState == UpgradeState.UpgradeComplete ||  //We have done at least one upgrade, but we are now done.
                                upgradeState == UpgradeState.None)       //no upgrade, just send the preample end bytes
                            {
                                ChangeUpgradeState(ref upgradeState, UpgradeState.WritingPreambleEnd);
                                // we've finished the preamble. Ack and return.
                                await connection.Output.WriteAsync(ServerSessionEncoder.AckResponseBytes);

                                await connection.Output.FlushAsync();

                                //terminal state
                                ChangeUpgradeState(ref upgradeState, UpgradeState.PreambleEndSent);
                            }
                            // If all bytes have already been consumed so the buffer has 0 length, AdvanceTo would throw
                            // as it's already been called.
                            if (buffer.Length > 0)
                            {
                                connection.Input.AdvanceTo(buffer.Start);
                            }

                            success = true;
                            await _next(connection);

                            return;
                        }

                        if (buffer.Length == 0)
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                if (!success)
                {
                    connection.Abort();
                }
            }
        }
        public async Task OnConnectedAsync(FramingConnection connection)
        {
            bool success = false;

            try
            {
                var decoder = connection.FramingDecoder as ServerSessionDecoder;
                Fx.Assert(decoder != null, "FramingDecoder must be non-null and an instance of ServerSessionDecoder");
                // first validate our content type
                ValidateContentType(connection, decoder);

                // next read any potential upgrades and finish consuming the preamble
                ReadOnlySequence <byte> buffer;
                while (true)
                {
                    System.IO.Pipelines.ReadResult readResult = await connection.Input.ReadAsync();

                    buffer = readResult.Buffer;
                    if (readResult.IsCompleted)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException());
                    }

                    while (buffer.Length > 0)
                    {
                        int bytesDecoded = decoder.Decode(buffer);
                        if (bytesDecoded > 0)
                        {
                            buffer = buffer.Slice(bytesDecoded);
                        }

                        switch (decoder.CurrentState)
                        {
                        case ServerSessionDecoder.State.UpgradeRequest:
                            ProcessUpgradeRequest(connection, decoder);

                            // accept upgrade
                            await connection.Output.WriteAsync(ServerSessionEncoder.UpgradeResponseBytes);

                            await connection.Output.FlushAsync();

                            //await context.Transport.Output.WriteAsync
                            //Connection.Write(ServerSessionEncoder.UpgradeResponseBytes, 0, ServerSessionEncoder.UpgradeResponseBytes.Length, true, timeoutHelper.RemainingTime());

                            try
                            {
                                connection.Input.AdvanceTo(buffer.Start);
                                buffer = ReadOnlySequence <byte> .Empty;
                                await UpgradeConnectionAsync(connection, decoder.Upgrade);

                                // TODO: ChannelBinding
                                //if (this.channelBindingProvider != null && this.channelBindingProvider.IsChannelBindingSupportEnabled)
                                //{
                                //    this.SetChannelBinding(this.channelBindingProvider.GetChannelBinding(this.upgradeAcceptor, ChannelBindingKind.Endpoint));
                                //}

                                //this.connectionBuffer = Connection.AsyncReadBuffer;
                            }
                            catch (Exception exception)
                            {
                                if (Fx.IsFatal(exception))
                                {
                                    throw;
                                }

                                // Audit Authentication Failure
                                //WriteAuditFailure(upgradeAcceptor as StreamSecurityUpgradeAcceptor, exception);
                                throw;
                            }
                            break;

                        case ServerSessionDecoder.State.Start:
                            SetupSecurityIfNecessary(connection);
                            // we've finished the preamble. Ack and continue to the next middleware.
                            await connection.Output.WriteAsync(ServerSessionEncoder.AckResponseBytes);

                            await connection.Output.FlushAsync();

                            connection.Input.AdvanceTo(buffer.Start);
                            await _next(connection);

                            success = true;
                            return;
                        }
                    }
                }
            }
            finally
            {
                if (!success)
                {
                    connection.Abort();
                }
            }
        }