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(); }
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(); } } }