public ProtoConnectionMiddleware(IList <IConnectionAdapter> adapters, ServiceContext serviceContext, IProtoApplication <TContext> application, ProtoProtocols protocols) { _serviceContext = serviceContext; _application = application; _protocols = protocols; // Keeping these around for now so progress can be made without updating tests _connectionAdapters = adapters; }
/// <summary> /// Create a new handler. /// </summary> /// <param name="pathBase">The base path.</param> /// <param name="application">The <see cref="IProtoApplication{TContext}"/>.</param> public ClientHandler(PathString pathBase, IProtoApplication <Context> application) { _application = application ?? throw new ArgumentNullException(nameof(application)); // PathString.StartsWithSegments that we use below requires the base path to not end in a slash. if (pathBase.HasValue && pathBase.Value.EndsWith("/")) { pathBase = new PathString(pathBase.Value.Substring(0, pathBase.Value.Length - 1)); } _pathBase = pathBase; }
public async Task StartAsync <TContext>(IProtoApplication <TContext> application, CancellationToken cancellationToken) { try { if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(CoreStrings.BigEndianNotSupported); } ValidateOptions(); if (_hasStarted) { // The server has already started and/or has not been cleaned up yet throw new InvalidOperationException(CoreStrings.ServerAlreadyStarted); } _hasStarted = true; ServiceContext.Heartbeat?.Start(); async Task OnBind(ListenOptions endpoint) { // Add the HTTP middleware as the terminal connection middleware endpoint.UseProtoServer(endpoint.ConnectionAdapters, ServiceContext, application, endpoint.Protocols); var connectionDelegate = endpoint.Build(); // Add the connection limit middleware if (Options.Limits.MaxConcurrentConnections.HasValue) { connectionDelegate = new ConnectionLimitMiddleware(connectionDelegate, Options.Limits.MaxConcurrentConnections.Value, Trace).OnConnectionAsync; } var connectionDispatcher = new ConnectionDispatcher(ServiceContext, connectionDelegate); var transport = _transportFactory.Create(endpoint, connectionDispatcher); _transports.Add(transport); await transport.BindAsync().ConfigureAwait(false); } await AddressBinder.BindAsync(_serverAddresses, Options, Trace, OnBind).ConfigureAwait(false); } catch (Exception ex) { Trace.LogCritical(0, ex, "Unable to start Simple."); Dispose(); throw; } }
internal ProtoContextBuilder(IProtoApplication <Context> application, bool allowSynchronousIO) { _application = application ?? throw new ArgumentNullException(nameof(application)); AllowSynchronousIO = allowSynchronousIO; _httpContext = new DefaultProtoContext(); var request = _httpContext.Request; request.Protocol = "HTTP/1.1"; request.Method = ProtoMethods.Get; _httpContext.Features.Set <IProtoBodyControlFeature>(this); _httpContext.Features.Set <IProtoResponseFeature>(_responseFeature); var requestLifetimeFeature = new ProtoRequestLifetimeFeature(); requestLifetimeFeature.RequestAborted = _requestAbortedSource.Token; _httpContext.Features.Set <IProtoRequestLifetimeFeature>(requestLifetimeFeature); _responseStream = new ResponseStream(ReturnResponseMessageAsync, AbortRequest, () => AllowSynchronousIO); _responseFeature.Body = _responseStream; }
public async Task StartAsync <TContext>(IProtoApplication <TContext> application, CancellationToken cancellationToken) { try { if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException("CoreStrings.BigEndianNotSupported"); } ValidateOptions(); if (_hasStarted) { // The server has already started and/or has not been cleaned up yet throw new InvalidOperationException("CoreStrings.ClientAlreadyStarted"); } _hasStarted = true; } catch (Exception ex) { Trace.LogCritical(0, ex, "Unable to start Standard."); Dispose(); throw; } }
public static IConnectionBuilder UseProtoServer <TContext>(this IConnectionBuilder builder, IList <IConnectionAdapter> adapters, ServiceContext serviceContext, IProtoApplication <TContext> application, ProtoProtocols protocols) { var middleware = new ProtoConnectionMiddleware <TContext>(adapters, serviceContext, application, protocols); return(builder.Use(next => { return middleware.OnConnectionAsync; })); }
public static IConnectionBuilder UseProtoServer <TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IProtoApplication <TContext> application, ProtoProtocols protocols) { return(builder.UseProtoServer(Array.Empty <IConnectionAdapter>(), serviceContext, application, protocols)); }
public async Task ProcessRequestsAsync <TContext>(IProtoApplication <TContext> httpApplication) { try { AdaptedPipeline adaptedPipeline = null; var adaptedPipelineTask = Task.CompletedTask; // _adaptedTransport must be set prior to wiring up callbacks // to allow the connection to be aborted prior to protocol selection. _adaptedTransport = _context.Transport; if (_context.ConnectionAdapters.Count > 0) { adaptedPipeline = new AdaptedPipeline(_adaptedTransport, new Pipe(AdaptedInputPipeOptions), new Pipe(AdaptedOutputPipeOptions), Log); _adaptedTransport = adaptedPipeline; } // This feature should never be null in Kestrel var connectionHeartbeatFeature = _context.ConnectionFeatures.Get <IConnectionHeartbeatFeature>(); Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!"); connectionHeartbeatFeature?.OnHeartbeat(state => ((ProtoConnection)state).Tick(), this); var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>(); Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!"); using (connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((ProtoConnection)state).StopProcessingNextRequest(), this)) { // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs. _timeoutControl.Initialize(_systemClock.UtcNowTicks); _context.ConnectionFeatures.Set <IConnectionTimeoutFeature>(_timeoutControl); if (adaptedPipeline != null) { // Stream can be null here and run async will close the connection in that case var stream = await ApplyConnectionAdaptersAsync(); adaptedPipelineTask = adaptedPipeline.RunAsync(stream); } IRequestProcessor requestProcessor = null; lock (_protocolSelectionLock) { // Ensure that the connection hasn't already been stopped. if (_protocolSelectionState == ProtocolSelectionState.Initializing) { var derivedContext = CreateDerivedContext(_adaptedTransport); switch (SelectProtocol()) { case ProtoProtocols.Proto1: // _http1Connection must be initialized before adding the connection to the connection manager requestProcessor = _http1Connection = new Proto1Connection(derivedContext); _protocolSelectionState = ProtocolSelectionState.Selected; break; case ProtoProtocols.Proto2: // _http2Connection must be initialized before yielding control to the transport thread, // to prevent a race condition where _http2Connection.Abort() is called just as // _http2Connection is about to be initialized. requestProcessor = new Proto2Connection(derivedContext); _protocolSelectionState = ProtocolSelectionState.Selected; break; case ProtoProtocols.None: // An error was already logged in SelectProtocol(), but we should close the connection. Abort(new ConnectionAbortedException(CoreStrings.ProtocolSelectionFailed)); break; default: // SelectProtocol() only returns Proto1, Proto2 or None. throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Proto1, Proto2 or None."); } _requestProcessor = requestProcessor; } } _context.Transport.Input.OnWriterCompleted( (_, state) => ((ProtoConnection)state).OnInputOrOutputCompleted(), this); _context.Transport.Output.OnReaderCompleted( (_, state) => ((ProtoConnection)state).OnInputOrOutputCompleted(), this); if (requestProcessor != null) { await requestProcessor.ProcessRequestsAsync(httpApplication); } await adaptedPipelineTask; } } catch (Exception ex) { Log.LogCritical(0, ex, $"Unexpected exception in {nameof(ProtoConnection)}.{nameof(ProcessRequestsAsync)}."); } finally { DisposeAdaptedConnections(); if (_http1Connection?.IsUpgraded == true) { _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne(); } } }
public Proto2Stream(IProtoApplication <TContext> application, Proto2StreamContext context) : base(context) { _application = application; }