コード例 #1
0
 public TestHttp1Connection(HttpConnectionContext context)
     : base(context)
 {
 }
コード例 #2
0
        public WebSocketsServerTransport(WebSocketOptions options, IDuplexPipe application, HttpConnectionContext connection, ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _options     = options;
            _application = application;
            _connection  = connection;

            // We create the logger with a string to preserve the logging namespace after the server side transport renames.
            _logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport");
        }
コード例 #3
0
    private async Task <bool> EnsureConnectionStateAsync(HttpConnectionContext connection, HttpContext context, HttpTransportType transportType, HttpTransportType supportedTransports, ConnectionLogScope logScope, HttpConnectionDispatcherOptions options)
    {
        if ((supportedTransports & transportType) == 0)
        {
            context.Response.ContentType = "text/plain";
            context.Response.StatusCode  = StatusCodes.Status404NotFound;
            Log.TransportNotSupported(_logger, transportType);
            await context.Response.WriteAsync($"{transportType} transport not supported by this end point type");

            return(false);
        }

        // Set the IHttpConnectionFeature now that we can access it.
        connection.Features.Set(context.Features.Get <IHttpConnectionFeature>());

        if (connection.TransportType == HttpTransportType.None)
        {
            connection.TransportType = transportType;
        }
        else if (connection.TransportType != transportType)
        {
            context.Response.ContentType = "text/plain";
            context.Response.StatusCode  = StatusCodes.Status400BadRequest;
            Log.CannotChangeTransport(_logger, connection.TransportType, transportType);
            await context.Response.WriteAsync("Cannot change transports mid-connection");

            return(false);
        }

        // Configure transport-specific features.
        if (transportType == HttpTransportType.LongPolling)
        {
            connection.HasInherentKeepAlive = true;

            // For long polling, the requests come and go but the connection is still alive.
            // To make the IHttpContextFeature work well, we make a copy of the relevant properties
            // to a new HttpContext. This means that it's impossible to affect the context
            // with subsequent requests.
            var existing = connection.HttpContext;
            if (existing == null)
            {
                CloneHttpContext(context, connection);
            }
            else
            {
                // Set the request trace identifier to the current http request handling the poll
                existing.TraceIdentifier = context.TraceIdentifier;

                // Don't copy the identity if it's a windows identity
                // We specifically clone the identity on first poll if it's a windows identity
                // If we swapped the new User here we'd have to dispose the old identities which could race with the application
                // trying to access the identity.
                if (!(context.User.Identity is WindowsIdentity))
                {
                    existing.User = context.User;
                }
            }
        }
        else
        {
            connection.HttpContext = context;
        }

        // Setup the connection state from the http context
        connection.User = connection.HttpContext?.User;

        UpdateExpiration(connection, context);

        // Set the Connection ID on the logging scope so that logs from now on will have the
        // Connection ID metadata set.
        logScope.ConnectionId = connection.ConnectionId;

        return(true);
    }
コード例 #4
0
    private static void CloneHttpContext(HttpContext context, HttpConnectionContext connection)
    {
        // The reason we're copying the base features instead of the HttpContext properties is
        // so that we can get all of the logic built into DefaultHttpContext to extract higher level
        // structure from the low level properties
        var existingRequestFeature = context.Features.GetRequiredFeature <IHttpRequestFeature>();

        var requestFeature = new HttpRequestFeature
        {
            Protocol    = existingRequestFeature.Protocol,
            Method      = existingRequestFeature.Method,
            Scheme      = existingRequestFeature.Scheme,
            Path        = existingRequestFeature.Path,
            PathBase    = existingRequestFeature.PathBase,
            QueryString = existingRequestFeature.QueryString,
            RawTarget   = existingRequestFeature.RawTarget
        };
        var requestHeaders = new Dictionary <string, StringValues>(existingRequestFeature.Headers.Count, StringComparer.OrdinalIgnoreCase);

        foreach (var header in existingRequestFeature.Headers)
        {
            requestHeaders[header.Key] = header.Value;
        }
        requestFeature.Headers = new HeaderDictionary(requestHeaders);

        var existingConnectionFeature = context.Features.Get <IHttpConnectionFeature>();
        var connectionFeature         = new HttpConnectionFeature();

        if (existingConnectionFeature != null)
        {
            connectionFeature.ConnectionId    = existingConnectionFeature.ConnectionId;
            connectionFeature.LocalIpAddress  = existingConnectionFeature.LocalIpAddress;
            connectionFeature.LocalPort       = existingConnectionFeature.LocalPort;
            connectionFeature.RemoteIpAddress = existingConnectionFeature.RemoteIpAddress;
            connectionFeature.RemotePort      = existingConnectionFeature.RemotePort;
        }

        // The response is a dud, you can't do anything with it anyways
        var responseFeature = new HttpResponseFeature();

        var features = new FeatureCollection();

        features.Set <IHttpRequestFeature>(requestFeature);
        features.Set <IHttpResponseFeature>(responseFeature);
        features.Set <IHttpResponseBodyFeature>(new StreamResponseBodyFeature(Stream.Null));
        features.Set <IHttpConnectionFeature>(connectionFeature);

        // REVIEW: We could strategically look at adding other features but it might be better
        // if we expose a callback that would allow the user to preserve HttpContext properties.

        var newHttpContext = new DefaultHttpContext(features);

        newHttpContext.TraceIdentifier = context.TraceIdentifier;

        newHttpContext.SetEndpoint(context.GetEndpoint());

        CloneUser(newHttpContext, context);

        connection.ServiceScope        = context.RequestServices.CreateAsyncScope();
        newHttpContext.RequestServices = connection.ServiceScope.Value.ServiceProvider;

        // REVIEW: This extends the lifetime of anything that got put into HttpContext.Items
        newHttpContext.Items = new Dictionary <object, object?>(context.Items);

        connection.HttpContext = newHttpContext;
    }
コード例 #5
0
        public LongPollingServerTransport(CancellationToken timeoutToken, PipeReader application, ILoggerFactory loggerFactory, HttpConnectionContext connection)
        {
            _timeoutToken = timeoutToken;
            _application  = application;

            _connection = connection;

            // We create the logger with a string to preserve the logging namespace after the server side transport renames.
            _logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Connections.Internal.Transports.LongPollingTransport");
        }
コード例 #6
0
        public WebSocketsTransport(WebSocketOptions options, IDuplexPipe application, HttpConnectionContext connection, ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _options     = options;
            _application = application;
            _connection  = connection;
            _logger      = loggerFactory.CreateLogger <WebSocketsTransport>();
        }
コード例 #7
0
ファイル: HttpServer.cs プロジェクト: Nangal/Stact
		static void AddHttpCompressionIfClientCanAcceptIt(HttpConnectionContext context)
		{
			string acceptEncoding = context.Request.Headers["Accept-Encoding"];

			if (string.IsNullOrEmpty(acceptEncoding))
				return;

			if ((acceptEncoding.IndexOf("gzip", StringComparison.InvariantCultureIgnoreCase) != -1))
			{
				context.SetResponseFilter(s => new GZipStream(s, CompressionMode.Compress, true));
				context.Response.Headers["Content-Encoding"] = "gzip";
			}
			else if (acceptEncoding.IndexOf("deflate", StringComparison.InvariantCultureIgnoreCase) != -1)
			{
				context.SetResponseFilter(s => new DeflateStream(s, CompressionMode.Compress, true));
				context.Response.Headers["Content-Encoding"] = "deflate";
			}
		}
コード例 #8
0
 public Http3ControlStream(IHttpApplication <TContext> application, Http3Connection connection, HttpConnectionContext context) : base(connection, context)
 {
     _application = application;
 }
コード例 #9
0
        public async Task CopyToAsyncDoesNotCopyBlocks()
        {
            var writeCount      = 0;
            var writeTcs        = new TaskCompletionSource <(byte[], int, int)>(TaskCreationOptions.RunContinuationsAsynchronously);
            var mockDestination = new Mock <Stream> {
                CallBase = true
            };

            mockDestination
            .Setup(m => m.WriteAsync(It.IsAny <byte[]>(), It.IsAny <int>(), It.IsAny <int>(), CancellationToken.None))
            .Callback((byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
            {
                writeTcs.SetResult((buffer, offset, count));
                writeCount++;
            })
            .Returns(Task.CompletedTask);

            using (var memoryPool = KestrelMemoryPool.Create())
            {
                var options   = new PipeOptions(pool: memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
                var pair      = DuplexPipe.CreateConnectionPair(options, options);
                var transport = pair.Transport;
                var http1ConnectionContext = new HttpConnectionContext
                {
                    ServiceContext     = new TestServiceContext(),
                    ConnectionFeatures = new FeatureCollection(),
                    Transport          = transport,
                    MemoryPool         = memoryPool,
                    TimeoutControl     = Mock.Of <ITimeoutControl>()
                };
                var http1Connection = new Http1Connection(http1ConnectionContext)
                {
                    HasStartedConsumingRequestBody = true
                };

                var headers = new HttpRequestHeaders {
                    HeaderContentLength = "12"
                };
                var body = Http1MessageBody.For(HttpVersion.Http11, headers, http1Connection);

                var copyToAsyncTask = body.CopyToAsync(mockDestination.Object);

                var bytes  = Encoding.ASCII.GetBytes("Hello ");
                var buffer = http1Connection.RequestBodyPipe.Writer.GetMemory(2048);
                Assert.True(MemoryMarshal.TryGetArray(buffer, out ArraySegment <byte> segment));
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length);
                http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length);
                await http1Connection.RequestBodyPipe.Writer.FlushAsync();

                // Verify the block passed to Stream.WriteAsync() is the same one incoming data was written into.
                Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task);

                // Verify the again when GetMemory returns the tail space of the same block.
                writeTcs = new TaskCompletionSource <(byte[], int, int)>(TaskCreationOptions.RunContinuationsAsynchronously);
                bytes    = Encoding.ASCII.GetBytes("World!");
                buffer   = http1Connection.RequestBodyPipe.Writer.GetMemory(2048);
                Assert.True(MemoryMarshal.TryGetArray(buffer, out segment));
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length);
                http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length);
                await http1Connection.RequestBodyPipe.Writer.FlushAsync();

                Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task);

                http1Connection.RequestBodyPipe.Writer.Complete();

                await copyToAsyncTask;

                Assert.Equal(2, writeCount);

                // Don't call body.StopAsync() because PumpAsync() was never called.
                http1Connection.RequestBodyPipe.Reader.Complete();
            }
        }
        public ServerSentEventsServerTransport(PipeReader application, string connectionId, HttpConnectionContext connection, ILoggerFactory loggerFactory)
        {
            _application  = application;
            _connectionId = connectionId;
            _connection   = connection;

            // We create the logger with a string to preserve the logging namespace after the server side transport renames.
            _logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Connections.Internal.Transports.ServerSentEventsTransport");
        }
コード例 #11
0
 public HttpTransport(HttpConnectionContext connection, string path)
 {
     Connection = connection;
     Path       = path;
 }
コード例 #12
0
        public async Task ProcessRequestsAsync <TContext>(IHttpApplication <TContext> application)
        {
            var streamListenerFeature = Context.ConnectionFeatures.Get <IQuicStreamListenerFeature>();

            // Start other three unidirectional streams here.
            var controlTask = CreateControlStream(application);
            var encoderTask = CreateEncoderStream(application);
            var decoderTask = CreateDecoderStream(application);

            try
            {
                while (true)
                {
                    var connectionContext = await streamListenerFeature.AcceptAsync();

                    if (connectionContext == null || _haveSentGoAway)
                    {
                        break;
                    }

                    var httpConnectionContext = new HttpConnectionContext
                    {
                        ConnectionId       = connectionContext.ConnectionId,
                        ConnectionContext  = connectionContext,
                        Protocols          = Context.Protocols,
                        ServiceContext     = Context.ServiceContext,
                        ConnectionFeatures = connectionContext.Features,
                        MemoryPool         = Context.MemoryPool,
                        Transport          = connectionContext.Transport,
                        TimeoutControl     = Context.TimeoutControl,
                        LocalEndPoint      = connectionContext.LocalEndPoint as IPEndPoint,
                        RemoteEndPoint     = connectionContext.RemoteEndPoint as IPEndPoint
                    };

                    var streamFeature = httpConnectionContext.ConnectionFeatures.Get <IQuicStreamFeature>();

                    if (!streamFeature.CanWrite)
                    {
                        // Unidirectional stream
                        var stream = new Http3ControlStream <TContext>(application, this, httpConnectionContext);
                        ThreadPool.UnsafeQueueUserWorkItem(stream, preferLocal: false);
                    }
                    else
                    {
                        // Keep track of highest stream id seen for GOAWAY
                        var streamId = streamFeature.StreamId;

                        HighestStreamId = streamId;

                        var http3Stream = new Http3Stream <TContext>(application, this, httpConnectionContext);
                        var stream      = http3Stream;
                        _streams[streamId] = http3Stream;
                        ThreadPool.UnsafeQueueUserWorkItem(stream, preferLocal: false);
                    }
                }
            }
            finally
            {
                // Abort all streams as connection has shutdown.
                foreach (var stream in _streams.Values)
                {
                    stream.Abort(new ConnectionAbortedException("Connection is shutting down."));
                }

                ControlStream.Abort(new ConnectionAbortedException("Connection is shutting down."));
                EncoderStream.Abort(new ConnectionAbortedException("Connection is shutting down."));
                DecoderStream.Abort(new ConnectionAbortedException("Connection is shutting down."));

                await controlTask;
                await encoderTask;
                await decoderTask;
            }
        }
コード例 #13
0
 public Http3Connection(HttpConnectionContext context)
 {
     Context      = context;
     DynamicTable = new DynamicTable(0);
 }