public virtual void Initialize(IHttpApplication httpApplication)
        {
            if(httpApplication == null)
                throw new ArgumentNullException("httpApplication");

            httpApplication.PostRequestHandlerExecute += (sender, e) => this.OnPostRequestHandlerExecute((HttpApplicationWrapper) (HttpApplication) sender);
        }
        private IServer BuildTestServerAndStart(TextReader reader,
                                                ISharedTextWriter writer,
                                                IHttpApplication<int> application)
        {
            var server = new StdioServer(reader, writer);
            server.Start(application);

            return server;
        }
        private IServer BuildTestServerAndStart(TextReader reader,
                                                ISharedTextWriter writer,
                                                IHttpApplication<int> application)
        {
            var factory = new StdioServerFactory(reader, writer);
            var server = factory.CreateServer(new ConfigurationBuilder().Build());
            server.Start(application);

            return server;
        }
示例#4
0
        /// <summary>
        /// Create a new handler.
        /// </summary>
        /// <param name="next">The pipeline entry point.</param>
        public ClientHandler(PathString pathBase, IHttpApplication<Context> application)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            _application = 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 virtual void OnPostRequestHandlerExecute(IHttpApplication httpApplication)
        {
            if(httpApplication == null)
                throw new ArgumentNullException("httpApplication");

            if(!this.HtmlInvestigator.IsHtmlResponse(httpApplication.Context))
                return;

            IEnumerable<IHtmlTransformer> htmlTransformers = this.HtmlTransformingContext.GetTransformers().ToArray();

            if(!htmlTransformers.Any())
                return;

            TransformableStream transformableStream = new TransformableStream(httpApplication.Response.Filter, httpApplication.Response.ContentEncoding);
            transformableStream.Transform += (sender, streamTransformingEventArgs) => this.OnTransform(streamTransformingEventArgs, htmlTransformers);

            httpApplication.Response.Filter = transformableStream;
        }
示例#6
0
        public void Init(IHttpApplication context)
        {
            Debug.WriteLine("AntiScrapeModule.Init");

            using (var container = new UnityContainer())
            {
                container.Configure(x =>
                {
                    x.AddRegistry<IoCRegistry>();
                });

                _storage = container.Resolve<IDataStorage>();
            }

            context.BeginRequest += OnBeginRequest;
            context.PostMapRequestHandler += OnPostMapRequestHandler;

            _application = context;
        }
示例#7
0
 public Http2Stream(IHttpApplication <TContext> application, Http2StreamContext context)
 {
     Initialize(context);
     _application = application;
 }
示例#8
0
 public Middle(IHttpApplication app)
 {
     _app = app;
 }
示例#9
0
        public void Start <TContext>(IHttpApplication <TContext> application, IKafkaBusSubscriber subscriber)
        {
            //TODO: Code a better way to prevent same server from starting twice.
            if (_disposables != null)
            {
                // The server has already started and/or has not been cleaned up yet
                throw new InvalidOperationException("Server has already started.");
            }

            _disposables = new Stack <IDisposable>();

            try {
                var information = this.Features.Get <IServerInformation>();

                if (information?.Subscriber == null)
                {
                    if (subscriber != null)
                    {
                        information = new ServerInformation()
                        {
                            Subscriber = subscriber
                        };
                        //information.Subscriber = subscriber;
                    }
                    else
                    {
                        throw new InvalidOperationException($"KafkaBus subscriber could not be found. To use the KafkaBus server, call app.{nameof(ServerExtensions.ConfigureKafkaBusServer)} in Startup.Configure method and specify a subscriber to use.");
                    }
                }
                else
                {
                    subscriber = information.Subscriber;
                }

                //TODO: Add _logger properly
                this._logger.LogInformation($"{nameof(Server)} is starting the KafkaBus host.");
                var host = new KafkaBusHost <TContext>(subscriber, application, this._applicationLifetime, this._logFactory);

                //Register host for disposal
                //TODO: Make IApplicationLifeTime.Stopping to stop polling the queue.
                this._applicationLifetime.ApplicationStopping.Register(() => {
                    //TODO: Make ApplicationStopping event stop dequeueing items (StopPollingQueue)
                    host.Dispose();
                });
                this._applicationLifetime.ApplicationStopped.Register(() => host.Dispose());

                _disposables.Push(host);

                host.Start();

                foreach (var name in subscriber.ConnectionNames)
                {
                    information.AddAddress(name);
                }
            }
            catch (Exception ex) {
                this._logger.LogError(ex.Message + Environment.NewLine + ex.StackTrace);
                Dispose();
                throw;
            }
        }
示例#10
0
        public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            var hostingUrlsPresent = _serverAddresses.Addresses.Count > 0;
            var serverAddressCopy  = _serverAddresses.Addresses.ToList();

            _serverAddresses.Addresses.Clear();

            if (_serverAddresses.PreferHostingUrls && hostingUrlsPresent)
            {
                if (_options.UrlPrefixes.Count > 0)
                {
                    _logger.LogWarning(LoggerEventIds.ClearedPrefixes, $"Overriding endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} since {nameof(IServerAddressesFeature.PreferHostingUrls)} is set to true." +
                                       $" Binding to address(es) '{string.Join(", ", _serverAddresses.Addresses)}' instead. ");

                    Listener.Options.UrlPrefixes.Clear();
                }

                UpdateUrlPrefixes(serverAddressCopy);
            }
            else if (_options.UrlPrefixes.Count > 0)
            {
                if (hostingUrlsPresent)
                {
                    _logger.LogWarning(LoggerEventIds.ClearedAddresses, $"Overriding address(es) '{string.Join(", ", _serverAddresses.Addresses)}'. " +
                                       $"Binding to endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} instead.");

                    _serverAddresses.Addresses.Clear();
                }
            }
            else if (hostingUrlsPresent)
            {
                UpdateUrlPrefixes(serverAddressCopy);
            }
            else if (Listener.RequestQueue.Created)
            {
                _logger.LogDebug(LoggerEventIds.BindingToDefault, $"No listening endpoints were configured. Binding to {Constants.DefaultServerAddress} by default.");

                Listener.Options.UrlPrefixes.Add(Constants.DefaultServerAddress);
            }
            // else // Attaching to an existing queue, don't add a default.

            // Can't call Start twice
            Debug.Assert(Application == null);

            Debug.Assert(application != null);

            Application = new ApplicationWrapper <TContext>(application);

            Listener.Start();

            // Update server addresses after we start listening as port 0
            // needs to be selected at the point of binding.
            foreach (var prefix in _options.UrlPrefixes)
            {
                _serverAddresses.Addresses.Add(prefix.FullPrefix);
            }

            // Dispatch to get off the SynchronizationContext and use UnsafeQueueUserWorkItem to avoid capturing the ExecutionContext
            ThreadPool.UnsafeQueueUserWorkItem(state => state.ActivateRequestProcessingLimits(), this, preferLocal: false);

            return(Task.CompletedTask);
        }
示例#11
0
        private async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                KestrelEventSource.Log.ConnectionStart(this);

                AdaptedPipeline adaptedPipeline     = null;
                var             adaptedPipelineTask = Task.CompletedTask;

                // _adaptedTransport must be set prior to adding the connection to the manager in order
                // to allow the connection to be aported prior to protocol selection.
                _adaptedTransport = _context.Transport;
                var application = _context.Application;


                if (_context.ConnectionAdapters.Count > 0)
                {
                    adaptedPipeline = new AdaptedPipeline(_adaptedTransport,
                                                          application,
                                                          new Pipe(AdaptedInputPipeOptions),
                                                          new Pipe(AdaptedOutputPipeOptions));

                    _adaptedTransport = adaptedPipeline;
                }

                // Do this before the first await so we don't yield control to the transport until we've
                // added the connection to the connection manager
                _context.ServiceContext.ConnectionManager.AddConnection(_context.HttpConnectionId, this);
                _lastTimestamp = _context.ServiceContext.SystemClock.UtcNow.Ticks;

                _context.ConnectionFeatures.Set <IConnectionTimeoutFeature>(this);

                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)
                    {
                        switch (SelectProtocol())
                        {
                        case HttpProtocols.Http1:
                            // _http1Connection must be initialized before adding the connection to the connection manager
                            requestProcessor        = _http1Connection = CreateHttp1Connection(_adaptedTransport, application);
                            _protocolSelectionState = ProtocolSelectionState.Selected;
                            break;

                        case HttpProtocols.Http2:
                            // _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        = CreateHttp2Connection(_adaptedTransport, application);
                            _protocolSelectionState = ProtocolSelectionState.Selected;
                            break;

                        case HttpProtocols.None:
                            // An error was already logged in SelectProtocol(), but we should close the connection.
                            Abort(ex: null);
                            break;

                        default:
                            // SelectProtocol() only returns Http1, Http2 or None.
                            throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                        }

                        _requestProcessor = requestProcessor;
                    }
                }

                if (requestProcessor != null)
                {
                    await requestProcessor.ProcessRequestsAsync(httpApplication);
                }

                await adaptedPipelineTask;
                await _socketClosedTcs.Task;
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                _context.ServiceContext.ConnectionManager.RemoveConnection(_context.HttpConnectionId);
                DisposeAdaptedConnections();

                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }

                KestrelEventSource.Log.ConnectionStop(this);
            }
        }
 public ApplicationWrapper(IHttpApplication <TContext> application)
 {
     _application = application;
 }
示例#13
0
        public async Task ProcessRequestAsync <TContext>(IHttpApplication <TContext> application) where TContext : notnull
        {
            Exception?error = null;

            try
            {
                while (_isClosed == 0)
                {
                    var result = await Input.ReadAsync();

                    var readableBuffer = result.Buffer;
                    var consumed       = readableBuffer.Start;
                    var examined       = readableBuffer.End;

                    try
                    {
                        if (!readableBuffer.IsEmpty)
                        {
                            while (Http3FrameReader.TryReadFrame(ref readableBuffer, _incomingFrame, out var framePayload))
                            {
                                Log.Http3FrameReceived(ConnectionId, _streamIdFeature.StreamId, _incomingFrame);

                                consumed = examined = framePayload.End;
                                await ProcessHttp3Stream(application, framePayload, result.IsCompleted&& readableBuffer.IsEmpty);
                            }
                        }

                        if (result.IsCompleted)
                        {
                            await OnEndStreamReceived();

                            return;
                        }
                    }
                    finally
                    {
                        Input.AdvanceTo(consumed, examined);
                    }
                }
            }
            catch (Http3StreamErrorException ex)
            {
                error = ex;
                Abort(new ConnectionAbortedException(ex.Message, ex), ex.ErrorCode);
            }
            catch (Http3ConnectionErrorException ex)
            {
                error = ex;
                _errorCodeFeature.Error = (long)ex.ErrorCode;

                _context.StreamLifetimeHandler.OnStreamConnectionError(ex);
            }
            catch (ConnectionAbortedException ex)
            {
                error = ex;
            }
            catch (ConnectionResetException ex)
            {
                error = ex;
                var resolvedErrorCode = _errorCodeFeature.Error >= 0 ? _errorCodeFeature.Error : 0;
                AbortCore(new IOException(CoreStrings.HttpStreamResetByClient, ex), (Http3ErrorCode)resolvedErrorCode);
            }
            catch (Exception ex)
            {
                error = ex;
                Log.LogWarning(0, ex, "Stream threw an unexpected exception.");
            }
            finally
            {
                var streamError = error as ConnectionAbortedException
                                  ?? new ConnectionAbortedException("The stream has completed.", error !);

                await Input.CompleteAsync();

                var appCompleted = _appCompleted?.Task ?? Task.CompletedTask;
                if (!appCompleted.IsCompletedSuccessfully)
                {
                    // At this point in the stream's read-side is complete. However, with HTTP/3
                    // the write-side of the stream can still be aborted by the client on request
                    // aborted.
                    //
                    // To get notification of request aborted we register to connection closed
                    // token. It will notify this type that the client has aborted the request
                    // and Kestrel will complete pipes and cancel the RequestAborted token.
                    //
                    // Only subscribe to this event after the stream's read-side is complete to
                    // avoid interactions between reading that is in-progress and an abort.
                    // This means while reading, read-side abort will handle getting abort notifications.
                    //
                    // We don't need to hang on to the CancellationTokenRegistration from register.
                    // The CTS is cleaned up in StreamContext.DisposeAsync.
                    //
                    // TODO: Consider a better way to provide this notification. For perf we want to
                    // make the ConnectionClosed CTS pay-for-play, and change this event to use
                    // something that is more lightweight than a CTS.
                    _context.StreamContext.ConnectionClosed.Register(static s =>
        private async Task ProcessHeadersFrameAsync <TContext>(IHttpApplication <TContext> application)
        {
            if (_currentHeadersStream != null)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorHeadersInterleaved(_incomingFrame.Type, _incomingFrame.StreamId, _currentHeadersStream.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.StreamId == 0)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamIdZero(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPadding && _incomingFrame.HeadersPadLength >= _incomingFrame.Length)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorPaddingTooLong(_incomingFrame.Type), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_incomingFrame.HeadersHasPriority && _incomingFrame.HeadersStreamDependency == _incomingFrame.StreamId)
            {
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamSelfDependency(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.PROTOCOL_ERROR);
            }

            if (_streams.TryGetValue(_incomingFrame.StreamId, out var stream))
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1
                //
                // ...an endpoint that receives any frames after receiving a frame with the
                // END_STREAM flag set MUST treat that as a connection error (Section 5.4.1)
                // of type STREAM_CLOSED, unless the frame is permitted as described below.
                //
                // (The allowed frame types after END_STREAM are WINDOW_UPDATE, RST_STREAM and PRIORITY)
                if (stream.EndStreamReceived)
                {
                    throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamHalfClosedRemote(_incomingFrame.Type, stream.StreamId), Http2ErrorCode.STREAM_CLOSED);
                }

                // This is the last chance for the client to send END_STREAM
                if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == 0)
                {
                    throw new Http2ConnectionErrorException(CoreStrings.Http2ErrorHeadersWithTrailersNoEndStream, Http2ErrorCode.PROTOCOL_ERROR);
                }

                // Since we found an active stream, this HEADERS frame contains trailers
                _currentHeadersStream      = stream;
                _requestHeaderParsingState = RequestHeaderParsingState.Trailers;

                var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
                await DecodeTrailersAsync(endHeaders, _incomingFrame.HeadersPayload);
            }
            else if (_incomingFrame.StreamId <= _highestOpenedStreamId)
            {
                // http://httpwg.org/specs/rfc7540.html#rfc.section.5.1.1
                //
                // The first use of a new stream identifier implicitly closes all streams in the "idle"
                // state that might have been initiated by that peer with a lower-valued stream identifier.
                //
                // If we couldn't find the stream, it was previously closed (either implicitly or with
                // END_STREAM or RST_STREAM).
                throw new Http2ConnectionErrorException(CoreStrings.FormatHttp2ErrorStreamClosed(_incomingFrame.Type, _incomingFrame.StreamId), Http2ErrorCode.STREAM_CLOSED);
            }
            else
            {
                // Start a new stream
                _currentHeadersStream = new Http2Stream(new Http2StreamContext
                {
                    ConnectionId          = ConnectionId,
                    StreamId              = _incomingFrame.StreamId,
                    ServiceContext        = _context.ServiceContext,
                    ConnectionFeatures    = _context.ConnectionFeatures,
                    MemoryPool            = _context.MemoryPool,
                    LocalEndPoint         = _context.LocalEndPoint,
                    RemoteEndPoint        = _context.RemoteEndPoint,
                    StreamLifetimeHandler = this,
                    FrameWriter           = _frameWriter
                });

                if ((_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_STREAM) == Http2HeadersFrameFlags.END_STREAM)
                {
                    await _currentHeadersStream.OnDataAsync(Constants.EmptyData, endStream : true);
                }

                _currentHeadersStream.Reset();

                var endHeaders = (_incomingFrame.HeadersFlags & Http2HeadersFrameFlags.END_HEADERS) == Http2HeadersFrameFlags.END_HEADERS;
                await DecodeHeadersAsync(application, endHeaders, _incomingFrame.HeadersPayload);
            }
        }
示例#15
0
    public async Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken) where TContext : notnull
    {
        try
        {
            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 options, CancellationToken onBindCancellationToken)
            {
                var hasHttp1 = options.Protocols.HasFlag(HttpProtocols.Http1);
                var hasHttp2 = options.Protocols.HasFlag(HttpProtocols.Http2);
                var hasHttp3 = options.Protocols.HasFlag(HttpProtocols.Http3);
                var hasTls   = options.IsTls;

                // Filter out invalid combinations.

                if (!hasTls)
                {
                    // Http/1 without TLS, no-op HTTP/2 and 3.
                    if (hasHttp1)
                    {
                        hasHttp2 = false;
                        hasHttp3 = false;
                    }
                    // Http/3 requires TLS. Note we only let it fall back to HTTP/1, not HTTP/2
                    else if (hasHttp3)
                    {
                        throw new InvalidOperationException("HTTP/3 requires HTTPS.");
                    }
                }

                // Quic isn't registered if it's not supported, throw if we can't fall back to 1 or 2
                if (hasHttp3 && _multiplexedTransportFactory is null && !(hasHttp1 || hasHttp2))
                {
                    throw new InvalidOperationException("This platform doesn't support QUIC or HTTP/3.");
                }

                // Disable adding alt-svc header if endpoint has configured not to or there is no
                // multiplexed transport factory, which happens if QUIC isn't supported.
                var addAltSvcHeader = !options.DisableAltSvcHeader && _multiplexedTransportFactory != null;

                // Add the HTTP middleware as the terminal connection middleware
                if (hasHttp1 || hasHttp2 ||
                    options.Protocols == HttpProtocols.None)    // TODO a test fails because it doesn't throw an exception in the right place
                                                                // when there is no HttpProtocols in KestrelServer, can we remove/change the test?
                {
                    if (_transportFactory is null)
                    {
                        throw new InvalidOperationException($"Cannot start HTTP/1.x or HTTP/2 server if no {nameof(IConnectionListenerFactory)} is registered.");
                    }

                    options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
                    var connectionDelegate = options.Build();

                    // Add the connection limit middleware
                    connectionDelegate = EnforceConnectionLimit(connectionDelegate, Options.Limits.MaxConcurrentConnections, Trace);

                    options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig, onBindCancellationToken).ConfigureAwait(false);
                }

                if (hasHttp3 && _multiplexedTransportFactory is not null)
                {
                    options.UseHttp3Server(ServiceContext, application, options.Protocols, addAltSvcHeader);
                    var multiplexedConnectionDelegate = ((IMultiplexedConnectionBuilder)options).Build();

                    // Add the connection limit middleware
                    multiplexedConnectionDelegate = EnforceConnectionLimit(multiplexedConnectionDelegate, Options.Limits.MaxConcurrentConnections, Trace);

                    options.EndPoint = await _transportManager.BindAsync(options.EndPoint, multiplexedConnectionDelegate, options, onBindCancellationToken).ConfigureAwait(false);
                }
            }

            AddressBindContext = new AddressBindContext(_serverAddresses, Options, Trace, OnBind);

            await BindAsync(cancellationToken).ConfigureAwait(false);
        }
        catch
        {
            // Don't log the error https://github.com/dotnet/aspnetcore/issues/29801
            Dispose();
            throw;
        }

        // Register the options with the event source so it can be logged (if necessary)
        KestrelEventSource.Log.AddServerOptions(Options);
    }
示例#16
0
 public TestFrame(IHttpApplication <TContext> application, FrameContext context)
     : base(application, context)
 {
 }
示例#17
0
        public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            SetHttpHandler(new Action <dynamic, dynamic>(async(req, res) =>
            {
                var resourceName = GetCurrentResourceName();

                var bodyStream = (req.method != "GET" && req.method != "HEAD")
                        ? await GetBodyStream(req)
                            : Stream.Null;

                var oldSc = SynchronizationContext.Current;
                SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

                var cts = new CancellationTokenSource();
                req.setCancelHandler(new Action(() =>
                {
                    cts.Cancel();
                }));

                await Task.Factory.StartNew(async() =>
                {
                    var owinEnvironment = new Dictionary <string, object>();
                    owinEnvironment["owin.RequestBody"] = bodyStream;

                    var headers = new HeaderDictionary();

                    foreach (var headerPair in req.headers)
                    {
                        headers.Add(headerPair.Key, new string[] { headerPair.Value.ToString() });
                    }

                    owinEnvironment["owin.RequestHeaders"] = headers;

                    owinEnvironment["owin.RequestMethod"]      = req.method;
                    owinEnvironment["owin.RequestPath"]        = req.path.Split('?')[0];
                    owinEnvironment["owin.RequestPathBase"]    = "/" + resourceName;
                    owinEnvironment["owin.RequestProtocol"]    = "HTTP/1.0";
                    owinEnvironment["owin.RequestQueryString"] = (req.path.Contains('?')) ? req.path.Split('?', 2)[1] : "";
                    owinEnvironment["owin.RequestScheme"]      = "http";

                    var outStream = new HttpOutStream(owinEnvironment, res);
                    owinEnvironment["owin.ResponseBody"] = outStream;

                    var outHeaders = new Dictionary <string, string[]>();
                    owinEnvironment["owin.ResponseHeaders"] = outHeaders;

                    owinEnvironment["owin.CallCancelled"] = cts.Token;
                    owinEnvironment["owin.Version"]       = "1.0";

                    var ofc     = new FxOwinFeatureCollection(owinEnvironment);
                    var context = application.CreateContext(new FeatureCollection(ofc));

                    try
                    {
                        await application.ProcessRequestAsync(context);
                        await ofc.InvokeOnStarting();
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"Exception while handling request. {ex}");

                        await ofc.InvokeOnCompleted();

                        application.DisposeContext(context, ex);

                        var errorText = Encoding.UTF8.GetBytes("Error.");

                        owinEnvironment["owin.ResponseStatusCode"] = 500;
                        await outStream.WriteAsync(errorText, 0, errorText.Length);
                        await outStream.EndStream();

                        return;
                    }

                    application.DisposeContext(context, null);

                    await outStream.EndStream();

                    await ofc.InvokeOnCompleted();
                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

                SynchronizationContext.SetSynchronizationContext(oldSc);
            }));

            return(Task.CompletedTask);
        }
示例#18
0
 public RequestContext(IHttpApplication <TContext> application, MessagePump messagePump, HttpSysListener server, uint?bufferSize, ulong requestId)
     : base(server, bufferSize, requestId)
 {
     _application = application;
     _messagePump = messagePump;
 }
示例#19
0
            internal RequestState(HttpRequestMessage request, PathString pathBase, IHttpApplication <Context> application)
            {
                _request              = request;
                _application          = application;
                _responseTcs          = new TaskCompletionSource <HttpResponseMessage>();
                _requestAbortedSource = new CancellationTokenSource();
                _pipelineFinished     = false;

                if (request.RequestUri.IsDefaultPort)
                {
                    request.Headers.Host = request.RequestUri.Host;
                }
                else
                {
                    request.Headers.Host = request.RequestUri.GetComponents(UriComponents.HostAndPort, UriFormat.UriEscaped);
                }

                var contextFeatures = new FeatureCollection();
                var requestFeature  = new RequestFeature();

                contextFeatures.Set <IHttpRequestFeature>(requestFeature);
                _responseFeature = new ResponseFeature();
                contextFeatures.Set <IHttpResponseFeature>(_responseFeature);
                var requestLifetimeFeature = new HttpRequestLifetimeFeature();

                contextFeatures.Set <IHttpRequestLifetimeFeature>(requestLifetimeFeature);

                requestFeature.Protocol = "HTTP/" + request.Version.ToString(fieldCount: 2);
                requestFeature.Scheme   = request.RequestUri.Scheme;
                requestFeature.Method   = request.Method.ToString();

                var        fullPath = PathString.FromUriComponent(request.RequestUri);
                PathString remainder;

                if (fullPath.StartsWithSegments(pathBase, out remainder))
                {
                    requestFeature.PathBase = pathBase.Value;
                    requestFeature.Path     = remainder.Value;
                }
                else
                {
                    requestFeature.PathBase = string.Empty;
                    requestFeature.Path     = fullPath.Value;
                }

                requestFeature.QueryString = QueryString.FromUriComponent(request.RequestUri).Value;

                foreach (var header in request.Headers)
                {
                    requestFeature.Headers.Append(header.Key, header.Value.ToArray());
                }
                var requestContent = request.Content;

                if (requestContent != null)
                {
                    foreach (var header in request.Content.Headers)
                    {
                        requestFeature.Headers.Append(header.Key, header.Value.ToArray());
                    }
                }

                _responseStream                       = new ResponseStream(ReturnResponseMessageAsync, AbortRequest);
                _responseFeature.Body                 = _responseStream;
                _responseFeature.StatusCode           = 200;
                requestLifetimeFeature.RequestAborted = _requestAbortedSource.Token;

                Context = application.CreateContext(contextFeatures);
            }
示例#20
0
 public void Start <TContext>(IHttpApplication <TContext> application)
 {
     this.Start(application, null);
 }
示例#21
0
 public void Start <TContext>(IHttpApplication <TContext> application)
 {
     _executor = new Executor <TContext>(application);
 }
示例#22
0
        public async Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken) where TContext : notnull
        {
            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 options, CancellationToken onBindCancellationToken)
                {
                    // INVESTIGATE: For some reason, MsQuic needs to bind before
                    // sockets for it to successfully listen. It also seems racy.
                    if ((options.Protocols & HttpProtocols.Http3) == HttpProtocols.Http3)
                    {
                        if (_multiplexedTransportFactory is null)
                        {
                            throw new InvalidOperationException($"Cannot start HTTP/3 server if no {nameof(IMultiplexedConnectionListenerFactory)} is registered.");
                        }

                        options.UseHttp3Server(ServiceContext, application);
                        var multiplexedConnectionDelegate = ((IMultiplexedConnectionBuilder)options).Build();

                        // Add the connection limit middleware
                        multiplexedConnectionDelegate = EnforceConnectionLimit(multiplexedConnectionDelegate, Options.Limits.MaxConcurrentConnections, Trace);

                        options.EndPoint = await _transportManager.BindAsync(options.EndPoint, multiplexedConnectionDelegate, options, onBindCancellationToken).ConfigureAwait(false);
                    }

                    // Add the HTTP middleware as the terminal connection middleware
                    if ((options.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1 ||
                        (options.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2 ||
                        options.Protocols == HttpProtocols.None)    // TODO a test fails because it doesn't throw an exception in the right place
                                                                    // when there is no HttpProtocols in KestrelServer, can we remove/change the test?
                    {
                        if (_transportFactory is null)
                        {
                            throw new InvalidOperationException($"Cannot start HTTP/1.x or HTTP/2 server if no {nameof(IConnectionListenerFactory)} is registered.");
                        }

                        options.UseHttpServer(ServiceContext, application, options.Protocols);
                        var connectionDelegate = options.Build();

                        // Add the connection limit middleware
                        connectionDelegate = EnforceConnectionLimit(connectionDelegate, Options.Limits.MaxConcurrentConnections, Trace);

                        options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig, onBindCancellationToken).ConfigureAwait(false);
                    }
                }

                AddressBindContext = new AddressBindContext(_serverAddresses, Options, Trace, OnBind);

                await BindAsync(cancellationToken).ConfigureAwait(false);
            }
            catch
            {
                // Don't log the error https://github.com/dotnet/aspnetcore/issues/29801
                Dispose();
                throw;
            }
        }
示例#23
0
        public async Task ProcessRequestAsync <TContext>(IHttpApplication <TContext> application) where TContext : notnull
        {
            Exception?error = null;

            try
            {
                while (_isClosed == 0)
                {
                    var result = await Input.ReadAsync();

                    var readableBuffer = result.Buffer;
                    var consumed       = readableBuffer.Start;
                    var examined       = readableBuffer.End;

                    try
                    {
                        if (!readableBuffer.IsEmpty)
                        {
                            while (Http3FrameReader.TryReadFrame(ref readableBuffer, _incomingFrame, out var framePayload))
                            {
                                Log.Http3FrameReceived(ConnectionId, _streamIdFeature.StreamId, _incomingFrame);

                                consumed = examined = framePayload.End;
                                await ProcessHttp3Stream(application, framePayload);
                            }
                        }

                        if (result.IsCompleted)
                        {
                            await OnEndStreamReceived();

                            return;
                        }
                    }

                    finally
                    {
                        Input.AdvanceTo(consumed, examined);
                    }
                }
            }
            // catch ConnectionResetException here?
            catch (Http3StreamErrorException ex)
            {
                error = ex;
                Abort(new ConnectionAbortedException(ex.Message, ex), ex.ErrorCode);
            }
            catch (Http3ConnectionErrorException ex)
            {
                error = ex;
                _errorCodeFeature.Error = (long)ex.ErrorCode;

                Log.Http3ConnectionError(_http3Connection.ConnectionId, ex);
                _http3Connection.Abort(new ConnectionAbortedException(ex.Message, ex), ex.ErrorCode);

                // TODO: HTTP/3 stream will be aborted by connection. Check this is correct.
            }
            catch (Exception ex)
            {
                error = ex;
                Log.LogWarning(0, ex, "Stream threw an unexpected exception.");
            }
            finally
            {
                var streamError = error as ConnectionAbortedException
                                  ?? new ConnectionAbortedException("The stream has completed.", error !);

                await Input.CompleteAsync();

                // Make sure application func is completed before completing writer.
                if (_appCompleted != null)
                {
                    await _appCompleted.Task;
                }

                try
                {
                    await _frameWriter.CompleteAsync();
                }
                catch
                {
                    Abort(streamError, Http3ErrorCode.ProtocolError);
                    throw;
                }
                finally
                {
                    await _context.StreamContext.DisposeAsync();

                    _http3Connection.RemoveStream(_streamIdFeature.StreamId);
                }
            }
        }
示例#24
0
 public IISHttpContextOfT(MemoryPool <byte> memoryPool, IHttpApplication <TContext> application, IntPtr pInProcessHandler, IISServerOptions options, IISHttpServer server, ILogger logger)
     : base(memoryPool, pInProcessHandler, options, server, logger)
 {
     _application = application;
 }
示例#25
0
 private Task ProcessHttp3Stream <TContext>(IHttpApplication <TContext> application, in ReadOnlySequence <byte> payload) where TContext : notnull
        public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            var hostingUrlsPresent = _serverAddresses.Addresses.Count > 0;

            if (_serverAddresses.PreferHostingUrls && hostingUrlsPresent)
            {
                if (_options.UrlPrefixes.Count > 0)
                {
                    LogHelper.LogWarning(_logger, $"Overriding endpoints added to {nameof(AzureRelayOptions.UrlPrefixes)} since {nameof(IServerAddressesFeature.PreferHostingUrls)} is set to true." +
                                         $" Binding to address(es) '{string.Join(", ", _serverAddresses.Addresses)}' instead. ");

                    Listener.Options.UrlPrefixes.Clear();
                }

                foreach (var value in _serverAddresses.Addresses)
                {
                    Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(value));
                }
            }
            else if (_options.UrlPrefixes.Count > 0)
            {
                if (hostingUrlsPresent)
                {
                    LogHelper.LogWarning(_logger, $"Overriding address(es) '{string.Join(", ", _serverAddresses.Addresses)}'. " +
                                         $"Binding to endpoints added to {nameof(AzureRelayOptions.UrlPrefixes)} instead.");

                    _serverAddresses.Addresses.Clear();
                }

                foreach (var prefix in _options.UrlPrefixes)
                {
                    _serverAddresses.Addresses.Add(prefix.FullPrefix);
                }
            }
            else if (hostingUrlsPresent)
            {
                foreach (var value in _serverAddresses.Addresses)
                {
                    Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(value));
                }
            }
            else
            {
                LogHelper.LogDebug(_logger, $"No listening endpoints were configured.");
                throw new InvalidOperationException("No listening endpoints were configured.");
            }

            // Can't call Start twice
            Contract.Assert(_application == null);
            Contract.Assert(application != null);

            _application = new ApplicationWrapper <TContext>(application);

            Listener.Start();

            return(Task.CompletedTask);
        }
示例#27
0
        public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
        {
            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            var hostingUrlsPresent = _serverAddresses.Addresses.Count > 0;

            if (_serverAddresses.PreferHostingUrls && hostingUrlsPresent)
            {
                if (_options.UrlPrefixes.Count > 0)
                {
                    LogHelper.LogWarning(_logger, $"Overriding endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} since {nameof(IServerAddressesFeature.PreferHostingUrls)} is set to true." +
                                         $" Binding to address(es) '{string.Join(", ", _serverAddresses.Addresses)}' instead. ");

                    Listener.Options.UrlPrefixes.Clear();
                }

                foreach (var value in _serverAddresses.Addresses)
                {
                    Listener.Options.UrlPrefixes.Add(value);
                }
            }
            else if (_options.UrlPrefixes.Count > 0)
            {
                if (hostingUrlsPresent)
                {
                    LogHelper.LogWarning(_logger, $"Overriding address(es) '{string.Join(", ", _serverAddresses.Addresses)}'. " +
                                         $"Binding to endpoints added to {nameof(HttpSysOptions.UrlPrefixes)} instead.");

                    _serverAddresses.Addresses.Clear();
                }

                foreach (var prefix in _options.UrlPrefixes)
                {
                    _serverAddresses.Addresses.Add(prefix.FullPrefix);
                }
            }
            else if (hostingUrlsPresent)
            {
                foreach (var value in _serverAddresses.Addresses)
                {
                    Listener.Options.UrlPrefixes.Add(value);
                }
            }
            else if (Listener.RequestQueue.Created)
            {
                LogHelper.LogDebug(_logger, $"No listening endpoints were configured. Binding to {Constants.DefaultServerAddress} by default.");

                _serverAddresses.Addresses.Add(Constants.DefaultServerAddress);
                Listener.Options.UrlPrefixes.Add(Constants.DefaultServerAddress);
            }
            // else // Attaching to an existing queue, don't add a default.

            // Can't call Start twice
            Contract.Assert(_application == null);

            Contract.Assert(application != null);

            _application = new ApplicationWrapper <TContext>(application);

            Listener.Start();

            ActivateRequestProcessingLimits();

            return(Task.CompletedTask);
        }
示例#28
0
 public Task StartRequestProcessing <TContext>(IHttpApplication <TContext> application)
 {
     return(_lifetimeTask = ProcessRequestsAsync(application));
 }
 public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
 {
     return(Task.CompletedTask);
 }
示例#30
0
 public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
 {
     this.Application = new ApplicationWrapper <TContext>(application);
     return(Task.CompletedTask);
 }
示例#31
0
            public Task StartAsync <TContext>(IHttpApplication <TContext> application, CancellationToken cancellationToken)
            {
                RequestDelegate = ctx => throw new NotSupportedException();

                return(Task.CompletedTask);
            }
示例#32
0
 public CompressMiddleware(IHttpApplication app)
 {
     _app = app;
 }
示例#33
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> httpApplication)
        {
            try
            {
                // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs.
                _timeoutControl.Initialize(_systemClock.UtcNowTicks);

                IRequestProcessor requestProcessor = null;

                switch (SelectProtocol())
                {
                case HttpProtocols.Http1:
                    // _http1Connection must be initialized before adding the connection to the connection manager
                    requestProcessor        = _http1Connection = new Http1Connection <TContext>(_context);
                    _protocolSelectionState = ProtocolSelectionState.Selected;
                    break;

                case HttpProtocols.Http2:
                    // _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 Http2Connection(_context);
                    _protocolSelectionState = ProtocolSelectionState.Selected;
                    break;

                case HttpProtocols.None:
                    // An error was already logged in SelectProtocol(), but we should close the connection.
                    break;

                default:
                    // SelectProtocol() only returns Http1, Http2 or None.
                    throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                }

                _requestProcessor = requestProcessor;

                if (requestProcessor != null)
                {
                    var connectionHeartbeatFeature            = _context.ConnectionFeatures.Get <IConnectionHeartbeatFeature>();
                    var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>();

                    // These features should never be null in Kestrel itself, if this middleware is ever refactored to run outside of kestrel,
                    // we'll need to handle these missing.
                    Debug.Assert(connectionHeartbeatFeature != null, nameof(IConnectionHeartbeatFeature) + " is missing!");
                    Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");

                    // Register the various callbacks once we're going to start processing requests

                    // The heart beat for various timeouts
                    connectionHeartbeatFeature?.OnHeartbeat(state => ((HttpConnection)state).Tick(), this);

                    // Register for graceful shutdown of the server
                    using var shutdownRegistration = connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this);

                    // Register for connection close
                    using var closedRegistration = _context.ConnectionContext.ConnectionClosed.Register(state => ((HttpConnection)state).OnConnectionClosed(), this);

                    await requestProcessor.ProcessRequestsAsync(httpApplication);
                }
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }
            }
        }
示例#34
0
 public static IHttpServer CreateEmbedHttpServer(IHttpApplication app, IHttpApplication errApp, bool enableIPv4, bool enableIPv6, bool bindAny, int port, int backlog)
 {
     return new Embed.HttpServer (app, errApp, enableIPv4, enableIPv6, bindAny, port, backlog);
 }
示例#35
0
 public Http3ControlStream(IHttpApplication <TContext> application, Http3StreamContext context, long?headerType) : base(context, headerType)
 {
     _application = application;
 }
示例#36
0
            internal RequestState(HttpRequestMessage request, PathString pathBase, IHttpApplication<Context> application)
            {
                _request = request;
                _application = application;
                _responseTcs = new TaskCompletionSource<HttpResponseMessage>();
                _requestAbortedSource = new CancellationTokenSource();
                _pipelineFinished = false;

                if (request.RequestUri.IsDefaultPort)
                {
                    request.Headers.Host = request.RequestUri.Host;
                }
                else
                {
                    request.Headers.Host = request.RequestUri.GetComponents(UriComponents.HostAndPort, UriFormat.UriEscaped);
                }

                Context = application.CreateContext(new FeatureCollection());
                var httpContext = Context.HttpContext;

                httpContext.Features.Set<IHttpRequestFeature>(new RequestFeature());
                _responseFeature = new ResponseFeature();
                httpContext.Features.Set<IHttpResponseFeature>(_responseFeature);
                var serverRequest = httpContext.Request;
                serverRequest.Protocol = "HTTP/" + request.Version.ToString(2);
                serverRequest.Scheme = request.RequestUri.Scheme;
                serverRequest.Method = request.Method.ToString();

                var fullPath = PathString.FromUriComponent(request.RequestUri);
                PathString remainder;
                if (fullPath.StartsWithSegments(pathBase, out remainder))
                {
                    serverRequest.PathBase = pathBase;
                    serverRequest.Path = remainder;
                }
                else
                {
                    serverRequest.PathBase = PathString.Empty;
                    serverRequest.Path = fullPath;
                }

                serverRequest.QueryString = QueryString.FromUriComponent(request.RequestUri);

                foreach (var header in request.Headers)
                {
                    serverRequest.Headers.Append(header.Key, header.Value.ToArray());
                }
                var requestContent = request.Content;
                if (requestContent != null)
                {
                    foreach (var header in request.Content.Headers)
                    {
                        serverRequest.Headers.Append(header.Key, header.Value.ToArray());
                    }
                }

                _responseStream = new ResponseStream(ReturnResponseMessage, AbortRequest);
                httpContext.Response.Body = _responseStream;
                httpContext.Response.StatusCode = 200;
                httpContext.RequestAborted = _requestAbortedSource.Token;
            }
示例#37
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <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 => ((HttpConnection)state).Tick(), this);

                var connectionLifetimeNotificationFeature = _context.ConnectionFeatures.Get <IConnectionLifetimeNotificationFeature>();

                Debug.Assert(connectionLifetimeNotificationFeature != null, nameof(IConnectionLifetimeNotificationFeature) + " is missing!");

                using (connectionLifetimeNotificationFeature?.ConnectionClosedRequested.Register(state => ((HttpConnection)state).StopProcessingNextRequest(), this))
                {
                    // Ensure TimeoutControl._lastTimestamp is initialized before anything that could set timeouts runs.
                    _timeoutControl.Initialize(_systemClock.UtcNow);

                    _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 HttpProtocols.Http1:
                                // _http1Connection must be initialized before adding the connection to the connection manager
                                requestProcessor        = _http1Connection = new Http1Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.Http2:
                                // _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 Http2Connection(derivedContext);
                                _protocolSelectionState = ProtocolSelectionState.Selected;
                                break;

                            case HttpProtocols.None:
                                // An error was already logged in SelectProtocol(), but we should close the connection.
                                Abort(ex: null);
                                break;

                            default:
                                // SelectProtocol() only returns Http1, Http2 or None.
                                throw new NotSupportedException($"{nameof(SelectProtocol)} returned something other than Http1, Http2 or None.");
                            }

                            _requestProcessor = requestProcessor;
                        }
                    }

                    _context.Transport.Input.OnWriterCompleted(
                        (_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
                        this);

                    _context.Transport.Output.OnReaderCompleted(
                        (_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
                        this);

                    if (requestProcessor != null)
                    {
                        await requestProcessor.ProcessRequestsAsync(httpApplication);
                    }

                    await adaptedPipelineTask;
                }
            }
            catch (Exception ex)
            {
                Log.LogCritical(0, ex, $"Unexpected exception in {nameof(HttpConnection)}.{nameof(ProcessRequestsAsync)}.");
            }
            finally
            {
                DisposeAdaptedConnections();

                if (_http1Connection?.IsUpgraded == true)
                {
                    _context.ServiceContext.ConnectionManager.UpgradedConnectionCount.ReleaseOne();
                }
            }
        }
示例#38
0
 public Http3ConnectionMiddleware(ServiceContext serviceContext, IHttpApplication <TContext> application)
 {
     _serviceContext = serviceContext;
     _application    = application;
 }
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> application)
        {
            Exception error     = null;
            var       errorCode = Http2ErrorCode.NO_ERROR;

            try
            {
                while (!_stopping)
                {
                    var result = await Input.ReadAsync();

                    var readableBuffer = result.Buffer;
                    var consumed       = readableBuffer.Start;
                    var examined       = readableBuffer.End;

                    try
                    {
                        if (!readableBuffer.IsEmpty)
                        {
                            if (ParsePreface(readableBuffer, out consumed, out examined))
                            {
                                break;
                            }
                        }
                        else if (result.IsCompleted)
                        {
                            return;
                        }
                    }
                    finally
                    {
                        Input.Advance(consumed, examined);
                    }
                }

                if (!_stopping)
                {
                    await _frameWriter.WriteSettingsAsync(_serverSettings);
                }

                while (!_stopping)
                {
                    var result = await Input.ReadAsync();

                    var readableBuffer = result.Buffer;
                    var consumed       = readableBuffer.Start;
                    var examined       = readableBuffer.End;

                    try
                    {
                        if (!readableBuffer.IsEmpty)
                        {
                            if (Http2FrameReader.ReadFrame(readableBuffer, _incomingFrame, out consumed, out examined))
                            {
                                Log.LogTrace($"Connection id {ConnectionId} received {_incomingFrame.Type} frame with flags 0x{_incomingFrame.Flags:x} and length {_incomingFrame.Length} for stream ID {_incomingFrame.StreamId}");
                                await ProcessFrameAsync <TContext>(application);
                            }
                        }
                        else if (result.IsCompleted)
                        {
                            return;
                        }
                    }
                    finally
                    {
                        Input.Advance(consumed, examined);
                    }
                }
            }
            catch (ConnectionResetException ex)
            {
                // Don't log ECONNRESET errors when there are no active streams on the connection. Browsers like IE will reset connections regularly.
                if (_streams.Count > 0)
                {
                    Log.RequestProcessingError(ConnectionId, ex);
                }

                error = ex;
            }
            catch (Http2ConnectionErrorException ex)
            {
                Log.Http2ConnectionError(ConnectionId, ex);
                error     = ex;
                errorCode = ex.ErrorCode;
            }
            catch (HPackDecodingException ex)
            {
                Log.HPackDecodingError(ConnectionId, _currentHeadersStream.StreamId, ex);
                error     = ex;
                errorCode = Http2ErrorCode.COMPRESSION_ERROR;
            }
            catch (Exception ex)
            {
                error     = ex;
                errorCode = Http2ErrorCode.INTERNAL_ERROR;
                throw;
            }
            finally
            {
                try
                {
                    foreach (var stream in _streams.Values)
                    {
                        stream.Abort(error);
                    }

                    await _frameWriter.WriteGoAwayAsync(_highestOpenedStreamId, errorCode);
                }
                finally
                {
                    Input.Complete();
                    _frameWriter.Abort(ex: null);
                }
            }
        }
示例#40
0
            public RequestState(Uri uri, PathString pathBase, CancellationToken cancellationToken, IHttpApplication<Context> application)
            {
                _clientWebSocketTcs = new TaskCompletionSource<WebSocket>();
                _application = application;

                // HttpContext
                Context = _application.CreateContext(new FeatureCollection());
                var httpContext = Context.HttpContext;

                // Request
                httpContext.Features.Set<IHttpRequestFeature>(new RequestFeature());
                var request = httpContext.Request;
                request.Protocol = "HTTP/1.1";
                var scheme = uri.Scheme;
                scheme = (scheme == "ws") ? "http" : scheme;
                scheme = (scheme == "wss") ? "https" : scheme;
                request.Scheme = scheme;
                request.Method = "GET";
                var fullPath = PathString.FromUriComponent(uri);
                PathString remainder;
                if (fullPath.StartsWithSegments(pathBase, out remainder))
                {
                    request.PathBase = pathBase;
                    request.Path = remainder;
                }
                else
                {
                    request.PathBase = PathString.Empty;
                    request.Path = fullPath;
                }
                request.QueryString = QueryString.FromUriComponent(uri);
                request.Headers.Add("Connection", new string[] { "Upgrade" });
                request.Headers.Add("Upgrade", new string[] { "websocket" });
                request.Headers.Add("Sec-WebSocket-Version", new string[] { "13" });
                request.Headers.Add("Sec-WebSocket-Key", new string[] { CreateRequestKey() });
                request.Body = Stream.Null;

                // Response
                httpContext.Features.Set<IHttpResponseFeature>(new ResponseFeature());
                var response = httpContext.Response;
                response.Body = Stream.Null;
                response.StatusCode = 200;

                // WebSocket
                httpContext.Features.Set<IHttpWebSocketFeature>(this);
            }
示例#41
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> application) where TContext : notnull
        {
            // An endpoint MAY avoid creating an encoder stream if it's not going to
            // be used(for example if its encoder doesn't wish to use the dynamic
            // table, or if the maximum size of the dynamic table permitted by the
            // peer is zero).

            // An endpoint MAY avoid creating a decoder stream if its decoder sets
            // the maximum capacity of the dynamic table to zero.

            // Don't create Encoder and Decoder as they aren't used now.

            Exception?error = null;
            ValueTask outboundControlStreamTask = default;

            try
            {
                var outboundControlStream = await CreateNewUnidirectionalStreamAsync(application);

                lock (_sync)
                {
                    OutboundControlStream = outboundControlStream;
                }

                // Don't delay on waiting to send outbound control stream settings.
                outboundControlStreamTask = ProcessOutboundControlStreamAsync(outboundControlStream);

                while (_isClosed == 0)
                {
                    // Don't pass a cancellation token to AcceptAsync.
                    // AcceptAsync will return null if the connection is gracefully shutting down or aborted.
                    var streamContext = await _multiplexedContext.AcceptAsync();

                    try
                    {
                        if (streamContext == null)
                        {
                            break;
                        }

                        var streamDirectionFeature = streamContext.Features.Get <IStreamDirectionFeature>();
                        var streamIdFeature        = streamContext.Features.Get <IStreamIdFeature>();

                        Debug.Assert(streamDirectionFeature != null);
                        Debug.Assert(streamIdFeature != null);

                        var httpConnectionContext = new Http3StreamContext(
                            streamContext.ConnectionId,
                            protocols: default,
                            connectionContext: null !, // TODO connection context is null here. Should we set it to anything?
                            _context.ServiceContext,
                            streamContext.Features,
                            _context.MemoryPool,
                            streamContext.LocalEndPoint as IPEndPoint,
                            streamContext.RemoteEndPoint as IPEndPoint,
                            streamContext.Transport,
                            _streamLifetimeHandler,
                            streamContext,
                            _clientSettings,
                            _serverSettings);
                        httpConnectionContext.TimeoutControl = _context.TimeoutControl;

                        if (!streamDirectionFeature.CanWrite)
                        {
                            // Unidirectional stream
                            var stream = new Http3ControlStream <TContext>(application, httpConnectionContext);
                            _streamLifetimeHandler.OnStreamCreated(stream);

                            ThreadPool.UnsafeQueueUserWorkItem(stream, preferLocal: false);
                        }
                        else
                        {
                            // Request stream
                            UpdateHighestStreamId(streamIdFeature.StreamId);

                            var stream = new Http3Stream <TContext>(application, httpConnectionContext);
                            _streamLifetimeHandler.OnStreamCreated(stream);

                            KestrelEventSource.Log.RequestQueuedStart(stream, AspNetCore.Http.HttpProtocol.Http3);
                            ThreadPool.UnsafeQueueUserWorkItem(stream, preferLocal: false);
                        }
                    }