示例#1
0
    public async Task KeepAliveTimeout_AfterRequestComplete_ConnectionClosed()
    {
        var requestHeaders = new[]
        {
            new KeyValuePair <string, string>(InternalHeaderNames.Method, "GET"),
            new KeyValuePair <string, string>(InternalHeaderNames.Path, "/"),
            new KeyValuePair <string, string>(InternalHeaderNames.Scheme, "http"),
        };

        var limits = _serviceContext.ServerOptions.Limits;

        await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout();

        await Http3Api.CreateControlStream();

        var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

        await controlStream.ExpectSettingsAsync().DefaultTimeout();

        var requestStream = await Http3Api.CreateRequestStream(requestHeaders, endStream : true);

        await requestStream.ExpectHeadersAsync();

        await requestStream.ExpectReceiveEndOfStream();

        await requestStream.OnDisposedTask.DefaultTimeout();

        Http3Api.AdvanceClock(limits.KeepAliveTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1));

        await Http3Api.WaitForConnectionStopAsync(4, false, expectedErrorCode : Http3ErrorCode.NoError);
    }
示例#2
0
    public async Task ControlStream_ClientToServer_Completes_ConnectionError()
    {
        var now = _serviceContext.MockSystemClock.UtcNow;

        await Http3Api.InitializeConnectionAsync(_noopApplication);

        var controlStream = await Http3Api.CreateControlStream(id : 0);

        await controlStream.SendSettingsAsync(new List <Http3PeerSetting>());

        await controlStream.EndStreamAsync().DefaultTimeout();

        // Wait for control stream to finish processing and exit.
        await controlStream.OnStreamCompletedTask.DefaultTimeout();

        Http3Api.TriggerTick(now);
        Http3Api.TriggerTick(now + TimeSpan.FromSeconds(1));

        await Http3Api.WaitForConnectionErrorAsync <Http3ConnectionErrorException>(
            ignoreNonGoAwayFrames : true,
            expectedLastStreamId : 0,
            expectedErrorCode : Http3ErrorCode.ClosedCriticalStream,
            matchExpectedErrorMessage : AssertExpectedErrorMessages,
            expectedErrorMessage : CoreStrings.Http3ErrorControlStreamClosed);
    }
        public async Task SETTINGS_MaxFieldSectionSizeSent_ServerReceivesValue()
        {
            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            var incomingSettings = await inboundControlStream.ExpectSettingsAsync();

            var defaultLimits = new KestrelServerLimits();

            Assert.Collection(incomingSettings,
                              kvp =>
            {
                Assert.Equal((long)Http3SettingType.MaxFieldSectionSize, kvp.Key);
                Assert.Equal(defaultLimits.MaxRequestHeadersTotalSize, kvp.Value);
            });

            var outboundcontrolStream = await Http3Api.CreateControlStream();

            await outboundcontrolStream.SendSettingsAsync(new List <Http3PeerSetting>
            {
                new Http3PeerSetting(Http3SettingType.MaxFieldSectionSize, 100)
            });

            var maxFieldSetting = await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();

            Assert.Equal(Http3SettingType.MaxFieldSectionSize, maxFieldSetting.Key);
            Assert.Equal(100, maxFieldSetting.Value);
        }
示例#4
0
    public async Task ControlStream_HeaderNotReceivedWithinRequestHeadersTimeout_StreamError_PendingStreamsEnabled()
    {
        Http3Api._serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true;

        var now    = _serviceContext.MockSystemClock.UtcNow;
        var limits = _serviceContext.ServerOptions.Limits;

        await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout();

        var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

        await controlStream.ExpectSettingsAsync().DefaultTimeout();

        var outboundControlStream = await Http3Api.CreateControlStream(id : null);

        await outboundControlStream.OnUnidentifiedStreamCreatedTask.DefaultTimeout();

        var serverInboundControlStream = Http3Api.Connection._unidentifiedStreams[outboundControlStream.StreamId];

        Http3Api.TriggerTick(now);
        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout);

        Assert.Equal((now + limits.RequestHeadersTimeout).Ticks, serverInboundControlStream.StreamTimeoutTicks);

        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout + TimeSpan.FromTicks(1));
    }
示例#5
0
    public async Task HEADERS_IncompleteFrameReceivedWithinRequestHeadersTimeout_StreamError()
    {
        var now    = _serviceContext.MockSystemClock.UtcNow;
        var limits = _serviceContext.ServerOptions.Limits;

        var requestStream = await Http3Api.InitializeConnectionAndStreamsAsync(_noopApplication, null).DefaultTimeout();

        var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

        await controlStream.ExpectSettingsAsync().DefaultTimeout();

        await requestStream.SendHeadersPartialAsync().DefaultTimeout();

        await requestStream.OnStreamCreatedTask;

        var serverRequestStream = Http3Api.Connection._streams[requestStream.StreamId];

        Http3Api.TriggerTick(now);
        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout);

        Assert.Equal((now + limits.RequestHeadersTimeout).Ticks, serverRequestStream.StreamTimeoutTicks);

        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout + TimeSpan.FromTicks(1));

        await requestStream.WaitForStreamErrorAsync(
            Http3ErrorCode.RequestRejected,
            AssertExpectedErrorMessages,
            CoreStrings.BadRequest_RequestHeadersTimeout);
    }
示例#6
0
        private async Task <ConnectionContext> MakeRequestAsync(int index, KeyValuePair <string, string>[] headers)
        {
            var requestStream = await Http3Api.CreateRequestStream();

            var streamContext = requestStream.StreamContext;

            await requestStream.SendHeadersAsync(headers);

            await requestStream.SendDataAsync(Encoding.ASCII.GetBytes($"Hello world {index}"));

            await requestStream.ExpectHeadersAsync();

            var responseData = await requestStream.ExpectDataAsync();

            Assert.Equal($"Hello world {index}", Encoding.ASCII.GetString(responseData.ToArray()));

            Assert.False(requestStream.Disposed, "Request is in progress and shouldn't be disposed.");

            await requestStream.SendDataAsync(Encoding.ASCII.GetBytes($"End {index}"), endStream : true);

            responseData = await requestStream.ExpectDataAsync();

            Assert.Equal($"End {index}", Encoding.ASCII.GetString(responseData.ToArray()));

            await requestStream.ExpectReceiveEndOfStream();

            await requestStream.OnStreamCompletedTask.DefaultTimeout();

            await requestStream.OnDisposedTask.DefaultTimeout();

            Assert.True(requestStream.Disposed, "Request is complete and should be disposed.");

            return(streamContext);
        }
        public async Task GOAWAY_GracefulServerShutdown_SendsGoAway(int connectionRequests, int expectedStreamId)
        {
            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            await inboundControlStream.ExpectSettingsAsync();

            for (var i = 0; i < connectionRequests; i++)
            {
                var request = await Http3Api.CreateRequestStream();

                await request.SendHeadersAsync(Headers);

                await request.EndStreamAsync();

                await request.ExpectReceiveEndOfStream();

                await request.OnStreamCompletedTask.DefaultTimeout();
            }

            // Trigger server shutdown.
            Http3Api.CloseServerGracefully();

            Assert.Null(await Http3Api.MultiplexedConnectionContext.AcceptAsync().DefaultTimeout());

            await Http3Api.WaitForConnectionStopAsync(expectedStreamId, false, expectedErrorCode : Http3ErrorCode.NoError);
        }
        public async Task GOAWAY_GracefulServerShutdownWithActiveRequest_SendsMultipleGoAways()
        {
            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            await inboundControlStream.ExpectSettingsAsync();

            var activeRequest = await Http3Api.CreateRequestStream();

            await activeRequest.SendHeadersAsync(Headers);

            // Trigger server shutdown.
            Http3Api.CloseServerGracefully();

            await Http3Api.WaitForGoAwayAsync(false, VariableLengthIntegerHelper.EightByteLimit);

            // Request made while shutting down is rejected.
            var rejectedRequest = await Http3Api.CreateRequestStream();

            await rejectedRequest.WaitForStreamErrorAsync(Http3ErrorCode.RequestRejected);

            // End active request.
            await activeRequest.EndStreamAsync();

            await activeRequest.ExpectReceiveEndOfStream();

            // Client aborts the connection.
            Http3Api.MultiplexedConnectionContext.Abort();

            await Http3Api.WaitForConnectionStopAsync(4, false, expectedErrorCode : Http3ErrorCode.NoError);
        }
        public async Task StreamPool_VariableMultipleStreamsInSequence_PooledStreamReused(int count)
        {
            var headers = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "Custom"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            };

            await Http3Api.InitializeConnectionAsync(_echoApplication);

            ConnectionContext first = null;
            ConnectionContext last  = null;

            for (var i = 0; i < count; i++)
            {
                Logger.LogInformation($"Iteration {i}");

                var streamContext = await MakeRequestAsync(i, headers, sendData : true, waitForServerDispose : true);

                first ??= streamContext;
                last = streamContext;

                Assert.Same(first, last);
            }
        }
示例#10
0
        public async Task ControlStream_RequestHeadersTimeoutMaxValue_ExpirationIsMaxValue()
        {
            var now    = _serviceContext.MockSystemClock.UtcNow;
            var limits = _serviceContext.ServerOptions.Limits;

            limits.RequestHeadersTimeout = TimeSpan.MaxValue;

            var headers = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "Custom"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            };

            await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout();

            var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

            await controlStream.ExpectSettingsAsync().DefaultTimeout();

            var outboundControlStream = await Http3Api.CreateControlStream(id : null);

            await outboundControlStream.OnStreamCreatedTask.DefaultTimeout();

            var serverInboundControlStream = Http3Api.Connection._streams[outboundControlStream.StreamId];

            Http3Api.TriggerTick(now);

            Assert.Equal(TimeSpan.MaxValue.Ticks, serverInboundControlStream.StreamTimeoutTicks);
        }
示例#11
0
        public async Task ControlStream_HeaderReceivedWithinRequestHeadersTimeout_StreamError()
        {
            var now     = _serviceContext.MockSystemClock.UtcNow;
            var limits  = _serviceContext.ServerOptions.Limits;
            var headers = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "Custom"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            };

            await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout();

            var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

            await controlStream.ExpectSettingsAsync().DefaultTimeout();

            var outboundControlStream = await Http3Api.CreateControlStream(id : null);

            await outboundControlStream.OnStreamCreatedTask.DefaultTimeout();

            Http3Api.TriggerTick(now);
            Http3Api.TriggerTick(now + limits.RequestHeadersTimeout);

            await outboundControlStream.WriteStreamIdAsync(id : 0);

            await outboundControlStream.OnHeaderReceivedTask.DefaultTimeout();

            Http3Api.TriggerTick(now + limits.RequestHeadersTimeout + TimeSpan.FromTicks(1));
        }
示例#12
0
        public async Task DATA_Received_TooSlowlyOnSecondStream_AbortsConnectionAfterNonAdditiveRateTimeout()
        {
            var mockSystemClock = _serviceContext.MockSystemClock;
            var limits          = _serviceContext.ServerOptions.Limits;

            // Use non-default value to ensure the min request and response rates aren't mixed up.
            limits.MinRequestBodyDataRate = new MinDataRate(480, TimeSpan.FromSeconds(2.5));

            Http3Api._timeoutControl.Initialize(mockSystemClock.UtcNow.Ticks);

            await Http3Api.InitializeConnectionAsync(_readRateApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            await inboundControlStream.ExpectSettingsAsync();

            var requestStream1 = await Http3Api.CreateRequestStream();

            // _maxData is 16 KiB, and 16 KiB / 240 bytes/sec ~= 68 secs which is far above the grace period.
            await requestStream1.SendHeadersAsync(ReadRateRequestHeaders(_maxData.Length), endStream : false);

            await requestStream1.SendDataAsync(_maxData, endStream : true);

            await requestStream1.ExpectHeadersAsync();

            await requestStream1.ExpectDataAsync();

            await requestStream1.ExpectReceiveEndOfStream();

            var requestStream2 = await Http3Api.CreateRequestStream();

            await requestStream2.SendHeadersAsync(ReadRateRequestHeaders(_maxData.Length), endStream : false);

            await requestStream2.SendDataAsync(_maxData, endStream : false);

            await requestStream2.ExpectHeadersAsync();

            await requestStream2.ExpectDataAsync();

            // Due to the imprecision of floating point math and the fact that TimeoutControl derives rate from elapsed
            // time for reads instead of vice versa like for writes, use a half-second instead of single-tick cushion.
            var timeToReadMaxData = TimeSpan.FromSeconds(_maxData.Length / limits.MinRequestBodyDataRate.BytesPerSecond) - TimeSpan.FromSeconds(.5);

            // Don't send any more data and advance just to and then past the rate timeout.
            Http3Api.AdvanceClock(timeToReadMaxData);

            _mockTimeoutHandler.Verify(h => h.OnTimeout(It.IsAny <TimeoutReason>()), Times.Never);

            Http3Api.AdvanceClock(TimeSpan.FromSeconds(1));

            _mockTimeoutHandler.Verify(h => h.OnTimeout(TimeoutReason.ReadDataRate), Times.Once);

            await Http3Api.WaitForConnectionErrorAsync <ConnectionAbortedException>(
                ignoreNonGoAwayFrames : false,
                expectedLastStreamId : null,
                Http3ErrorCode.InternalError,
                null);

            _mockTimeoutHandler.VerifyNoOtherCalls();
        }
         nameof(HeaderNames.Origin), "server.example.com")] // no authority
    public async Task WebTransportHandshake_IncorrectHeadersRejects(long error, string targetErrorMessage, params string[] headers)
    {
        _serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true;

        await Http3Api.InitializeConnectionAsync(_noopApplication);

        var controlStream = await Http3Api.CreateControlStream();

        var controlStream2 = await Http3Api.GetInboundControlStream();

        var settings = new Http3PeerSettings()
        {
            EnableWebTransport = 1,
            H3Datagram         = 1,
        };

        await controlStream.SendSettingsAsync(settings.GetNonProtocolDefaults());

        var response1 = await controlStream2.ExpectSettingsAsync();

        await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();

        Assert.Equal(1, response1[(long)Http3SettingType.EnableWebTransport]);

        var headersConnectFrame = new List <KeyValuePair <string, string> >();

        for (var i = 0; i < headers.Length; i += 2)
        {
            headersConnectFrame.Add(new KeyValuePair <string, string>(GetHeaderFromName(headers[i]), headers[i + 1]));
        }

        var requestStream = await Http3Api.CreateRequestStream(headersConnectFrame);

        await requestStream.WaitForStreamErrorAsync((Http3ErrorCode)error, AssertExpectedErrorMessages, GetCoreStringFromName(targetErrorMessage));
    }
示例#14
0
        public async Task HEADERS_Received_ContainsExpect100Continue_100ContinueSent()
        {
            await Http3Api.InitializeConnectionAsync(async context =>
            {
                var buffer   = new byte[16 * 1024];
                var received = 0;

                while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await context.Response.Body.WriteAsync(buffer, 0, received);
                }
            });

            await Http3Api.CreateControlStream();

            await Http3Api.GetInboundControlStream();

            var requestStream = await Http3Api.CreateRequestStream();

            var expectContinueRequestHeaders = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "POST"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "127.0.0.1"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Expect, "100-continue"),
            };

            await requestStream.SendHeadersAsync(expectContinueRequestHeaders);

            var frame = await requestStream.ReceiveFrameAsync();

            Assert.Equal(Http3FrameType.Headers, frame.Type);

            var continueBytesQpackEncoded = new byte[] { 0x00, 0x00, 0xff, 0x00 };

            Assert.Equal(continueBytesQpackEncoded, frame.PayloadSequence.ToArray());

            await requestStream.SendDataAsync(Encoding.ASCII.GetBytes("Hello world"), endStream : false);

            var headers = await requestStream.ExpectHeadersAsync();

            Assert.Equal("200", headers[HeaderNames.Status]);

            var responseData = await requestStream.ExpectDataAsync();

            Assert.Equal("Hello world", Encoding.ASCII.GetString(responseData.ToArray()));

            Assert.False(requestStream.Disposed, "Request is in progress and shouldn't be disposed.");

            await requestStream.SendDataAsync(Encoding.ASCII.GetBytes($"End"), endStream : true);

            responseData = await requestStream.ExpectDataAsync();

            Assert.Equal($"End", Encoding.ASCII.GetString(responseData.ToArray()));

            await requestStream.ExpectReceiveEndOfStream();
        }
示例#15
0
    public async Task ResponseTrailers_MultipleStreams_Reset()
    {
        var requestHeaders = new[]
        {
            new KeyValuePair <string, string>(HeaderNames.Method, "GET"),
            new KeyValuePair <string, string>(HeaderNames.Path, "/hello"),
            new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
            new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            new KeyValuePair <string, string>(HeaderNames.ContentType, "application/json")
        };

        var requestCount = 0;
        IHeaderDictionary trailersFirst = null;
        IHeaderDictionary trailersLast  = null;
        await Http3Api.InitializeConnectionAsync(context =>
        {
            var trailersFeature = context.Features.Get <IHttpResponseTrailersFeature>();
            if (requestCount == 0)
            {
                trailersFirst            = new ResponseTrailersWrapper(trailersFeature.Trailers);
                trailersFeature.Trailers = trailersFirst;
            }
            else
            {
                trailersLast = trailersFeature.Trailers;
            }
            trailersFeature.Trailers[$"trailer-{requestCount++}"] = "true";
            return(Task.CompletedTask);
        });


        for (int i = 0; i < 3; i++)
        {
            var requestStream = await Http3Api.CreateRequestStream();

            await requestStream.SendHeadersAsync(requestHeaders, endStream : true);

            var responseHeaders = await requestStream.ExpectHeadersAsync();

            var data = await requestStream.ExpectTrailersAsync();

            Assert.Single(data);
            Assert.True(data.TryGetValue($"trailer-{i}", out var trailerValue) && bool.Parse(trailerValue));

            await requestStream.ExpectReceiveEndOfStream();

            await requestStream.OnDisposedTask.DefaultTimeout();
        }

        Assert.NotNull(trailersFirst);
        Assert.NotNull(trailersLast);
        Assert.NotSame(trailersFirst, trailersLast);
    }
示例#16
0
    public async Task HEADERS_HeaderFrameReceivedWithinRequestHeadersTimeout_Success(bool pendingStreamsEnabled)
    {
        Http3Api._serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = pendingStreamsEnabled;

        var now     = _serviceContext.MockSystemClock.UtcNow;
        var limits  = _serviceContext.ServerOptions.Limits;
        var headers = new[]
        {
            new KeyValuePair <string, string>(InternalHeaderNames.Method, "Custom"),
            new KeyValuePair <string, string>(InternalHeaderNames.Path, "/"),
            new KeyValuePair <string, string>(InternalHeaderNames.Scheme, "http"),
            new KeyValuePair <string, string>(InternalHeaderNames.Authority, "localhost:80"),
        };

        var requestStream = await Http3Api.InitializeConnectionAndStreamsAsync(_noopApplication, null).DefaultTimeout();

        var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

        await controlStream.ExpectSettingsAsync().DefaultTimeout();

        dynamic serverRequestStream;

        if (pendingStreamsEnabled)
        {
            await requestStream.OnUnidentifiedStreamCreatedTask.DefaultTimeout();

            serverRequestStream = Http3Api.Connection._unidentifiedStreams[requestStream.StreamId];
        }
        else
        {
            await requestStream.OnStreamCreatedTask.DefaultTimeout();

            serverRequestStream = Http3Api.Connection._streams[requestStream.StreamId];
        }

        Http3Api.TriggerTick(now);
        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout);

        Assert.Equal((now + limits.RequestHeadersTimeout).Ticks, serverRequestStream.StreamTimeoutTicks);

        await requestStream.SendHeadersAsync(headers).DefaultTimeout();

        await requestStream.OnHeaderReceivedTask.DefaultTimeout();

        Http3Api.TriggerTick(now + limits.RequestHeadersTimeout + TimeSpan.FromTicks(1));

        await requestStream.SendDataAsync(Memory <byte> .Empty, endStream : true);

        await requestStream.ExpectHeadersAsync();

        await requestStream.ExpectReceiveEndOfStream();
    }
示例#17
0
        public async Task InboundStreams_CreateMultiple_ConnectionError(int streamId, string name)
        {
            await Http3Api.InitializeConnectionAsync(_noopApplication);

            await Http3Api.CreateControlStream(streamId);

            await Http3Api.CreateControlStream(streamId);

            await Http3Api.WaitForConnectionErrorAsync <Http3ConnectionErrorException>(
                ignoreNonGoAwayFrames : true,
                expectedLastStreamId : 0,
                expectedErrorCode : Http3ErrorCode.StreamCreationError,
                expectedErrorMessage : CoreStrings.FormatHttp3ControlStreamErrorMultipleInboundStreams(name));
        }
示例#18
0
    public async Task KeepAliveTimeout_ControlStreamNotReceived_ConnectionClosed()
    {
        var limits = _serviceContext.ServerOptions.Limits;

        await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout();

        var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout();

        await controlStream.ExpectSettingsAsync().DefaultTimeout();

        Http3Api.AdvanceClock(limits.KeepAliveTimeout + TimeSpan.FromTicks(1));

        await Http3Api.WaitForConnectionStopAsync(0, false, expectedErrorCode : Http3ErrorCode.NoError);
    }
示例#19
0
        public async Task GracefulServerShutdownClosesConnection()
        {
            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            await inboundControlStream.ExpectSettingsAsync();

            // Trigger server shutdown.
            Http3Api.CloseConnectionGracefully();

            Assert.Null(await Http3Api.MultiplexedConnectionContext.AcceptAsync().DefaultTimeout());

            await Http3Api.WaitForConnectionStopAsync(0, false, expectedErrorCode : Http3ErrorCode.NoError);
        }
示例#20
0
        public async Task ControlStream_ClientToServer_UnexpectedFrameType_ConnectionError(string frameType)
        {
            await Http3Api.InitializeConnectionAsync(_noopApplication);

            var controlStream = await Http3Api.CreateControlStream();

            var f = Enum.Parse <Http3FrameType>(frameType);
            await controlStream.SendFrameAsync(f, Memory <byte> .Empty);

            await Http3Api.WaitForConnectionErrorAsync <Http3ConnectionErrorException>(
                ignoreNonGoAwayFrames : true,
                expectedLastStreamId : 0,
                expectedErrorCode : Http3ErrorCode.UnexpectedFrame,
                expectedErrorMessage : CoreStrings.FormatHttp3ErrorUnsupportedFrameOnControlStream(Http3Formatting.ToFormattedType(f)));
        }
示例#21
0
        public async Task ControlStream_ClientToServer_ClientCloses_ConnectionError()
        {
            await Http3Api.InitializeConnectionAsync(_noopApplication);

            var controlStream = await Http3Api.CreateControlStream(id : 0);

            await controlStream.SendSettingsAsync(new List <Http3PeerSetting>());

            await controlStream.EndStreamAsync();

            await Http3Api.WaitForConnectionErrorAsync <Http3ConnectionErrorException>(
                ignoreNonGoAwayFrames : true,
                expectedLastStreamId : 0,
                expectedErrorCode : Http3ErrorCode.ClosedCriticalStream,
                expectedErrorMessage : CoreStrings.Http3ErrorControlStreamClientClosedInbound);
        }
示例#22
0
        public async Task ResponseDrain_SlowerThanMinimumDataRate_AbortsConnection()
        {
            var now             = _serviceContext.MockSystemClock.UtcNow;
            var limits          = _serviceContext.ServerOptions.Limits;
            var mockSystemClock = _serviceContext.MockSystemClock;

            // Use non-default value to ensure the min request and response rates aren't mixed up.
            limits.MinResponseDataRate = new MinDataRate(480, TimeSpan.FromSeconds(2.5));

            await Http3Api.InitializeConnectionAsync(_noopApplication);

            var inboundControlStream = await Http3Api.GetInboundControlStream();

            await inboundControlStream.ExpectSettingsAsync();

            var requestStream = await Http3Api.CreateRequestStream();

            requestStream.StartStreamDisposeTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            await requestStream.SendHeadersAsync(new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Method, "GET"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            }, endStream : true);

            await requestStream.OnDisposingTask.DefaultTimeout();

            Http3Api.TriggerTick(now);
            Assert.Null(requestStream.StreamContext._error);

            Http3Api.TriggerTick(now + TimeSpan.FromTicks(1));
            Assert.Null(requestStream.StreamContext._error);

            Http3Api.TriggerTick(now + limits.MinResponseDataRate.GracePeriod + TimeSpan.FromTicks(1));

            requestStream.StartStreamDisposeTcs.TrySetResult();

            await Http3Api.WaitForConnectionErrorAsync <ConnectionAbortedException>(
                ignoreNonGoAwayFrames : false,
                expectedLastStreamId : 4,
                Http3ErrorCode.InternalError,
                expectedErrorMessage : CoreStrings.ConnectionTimedBecauseResponseMininumDataRateNotSatisfied);

            Assert.Contains(TestSink.Writes, w => w.EventId.Name == "ResponseMinimumDataRateNotSatisfied");
        }
示例#23
0
    public async Task DATA_Received_SlowlyWhenRateLimitDisabledPerRequest_DoesNotAbortConnection()
    {
        var mockSystemClock = _serviceContext.MockSystemClock;
        var limits          = _serviceContext.ServerOptions.Limits;

        // Use non-default value to ensure the min request and response rates aren't mixed up.
        limits.MinRequestBodyDataRate = new MinDataRate(480, TimeSpan.FromSeconds(2.5));

        Http3Api._timeoutControl.Initialize(mockSystemClock.UtcNow.Ticks);

        await Http3Api.InitializeConnectionAsync(context =>
        {
            // Completely disable rate limiting for this stream.
            context.Features.Get <IHttpMinRequestBodyDataRateFeature>().MinDataRate = null;
            return(_readRateApplication(context));
        });

        var inboundControlStream = await Http3Api.GetInboundControlStream();

        await inboundControlStream.ExpectSettingsAsync();

        Http3Api.OutboundControlStream = await Http3Api.CreateControlStream();

        // _helloWorldBytes is 12 bytes, and 12 bytes / 240 bytes/sec = .05 secs which is far below the grace period.
        var requestStream = await Http3Api.CreateRequestStream(ReadRateRequestHeaders(_helloWorldBytes.Length), endStream : false);

        await requestStream.SendDataAsync(_helloWorldBytes, endStream : false);

        await requestStream.ExpectHeadersAsync();

        await requestStream.ExpectDataAsync();

        // Don't send any more data and advance just to and then past the grace period.
        Http3Api.AdvanceClock(limits.MinRequestBodyDataRate.GracePeriod);

        _mockTimeoutHandler.Verify(h => h.OnTimeout(It.IsAny <TimeoutReason>()), Times.Never);

        Http3Api.AdvanceClock(TimeSpan.FromTicks(1));

        _mockTimeoutHandler.Verify(h => h.OnTimeout(It.IsAny <TimeoutReason>()), Times.Never);

        await requestStream.SendDataAsync(_helloWorldBytes, endStream : true);

        await requestStream.ExpectReceiveEndOfStream();

        _mockTimeoutHandler.VerifyNoOtherCalls();
    }
示例#24
0
        public async Task CreateRequestStream_RequestCompleted_Disposed()
        {
            var appCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
            await Http3Api.InitializeConnectionAsync(async context =>
            {
                var buffer   = new byte[16 * 1024];
                var received = 0;

                while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await context.Response.Body.WriteAsync(buffer, 0, received);
                }

                await appCompletedTcs.Task;
            });

            await Http3Api.CreateControlStream();

            await Http3Api.GetInboundControlStream();

            var requestStream = await Http3Api.CreateRequestStream();

            var headers = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "Custom"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            };

            await requestStream.SendHeadersAsync(headers);

            await requestStream.SendDataAsync(Encoding.ASCII.GetBytes("Hello world"), endStream : true);

            Assert.False(requestStream.Disposed);

            appCompletedTcs.SetResult();
            await requestStream.ExpectHeadersAsync();

            var responseData = await requestStream.ExpectDataAsync();

            Assert.Equal("Hello world", Encoding.ASCII.GetString(responseData.ToArray()));

            await requestStream.OnDisposedTask.DefaultTimeout();

            Assert.True(requestStream.Disposed);
        }
示例#25
0
        public async Task StreamPool_MultipleStreamsInSequence_PooledStreamReused()
        {
            var headers = new[]
            {
                new KeyValuePair <string, string>(HeaderNames.Method, "Custom"),
                new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
                new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
            };

            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var streamContext1 = await MakeRequestAsync(0, headers, sendData : true, waitForServerDispose : true);

            var streamContext2 = await MakeRequestAsync(1, headers, sendData : true, waitForServerDispose : true);

            Assert.Same(streamContext1, streamContext2);
        }
示例#26
0
        public async Task ControlStream_ServerToClient_ErrorInitializing_ConnectionError()
        {
            Http3Api.OnCreateServerControlStream = testStreamContext =>
            {
                var controlStream = new Microsoft.AspNetCore.Testing.Http3ControlStream(Http3Api, testStreamContext);

                // Make server connection error when trying to write to control stream.
                controlStream.StreamContext.Transport.Output.Complete();

                return(controlStream);
            };

            await Http3Api.InitializeConnectionAsync(_noopApplication);

            Http3Api.AssertConnectionError <Http3ConnectionErrorException>(
                expectedErrorCode: Http3ErrorCode.ClosedCriticalStream,
                expectedErrorMessage: CoreStrings.Http3ControlStreamErrorInitializingOutbound);
        }
示例#27
0
    public async Task WebTransportHandshake_ClientToServerPasses()
    {
        _serviceContext.ServerOptions.EnableWebTransportAndH3Datagrams = true;

        await Http3Api.InitializeConnectionAsync(_noopApplication);

        var controlStream = await Http3Api.CreateControlStream();

        var controlStream2 = await Http3Api.GetInboundControlStream();

        var settings = new Http3PeerSettings()
        {
            EnableWebTransport = 1,
            H3Datagram         = 1,
        };

        await controlStream.SendSettingsAsync(settings.GetNonProtocolDefaults());

        var response1 = await controlStream2.ExpectSettingsAsync();

        await Http3Api.ServerReceivedSettingsReader.ReadAsync().DefaultTimeout();

        Assert.Equal(1, response1[(long)Http3SettingType.EnableWebTransport]);

        var requestStream = await Http3Api.CreateRequestStream();

        var headersConnectFrame = new[]
        {
            new KeyValuePair <string, string>(HeaderNames.Method, "CONNECT"),
            new KeyValuePair <string, string>(HeaderNames.Protocol, "webtransport"),
            new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
            new KeyValuePair <string, string>(HeaderNames.Path, "/"),
            new KeyValuePair <string, string>(HeaderNames.Authority, "server.example.com"),
            new KeyValuePair <string, string>(HeaderNames.Origin, "server.example.com")
        };

        await requestStream.SendHeadersAsync(headersConnectFrame);

        var response2 = await requestStream.ExpectHeadersAsync();

        Assert.Equal((int)HttpStatusCode.OK, Convert.ToInt32(response2[HeaderNames.Status], null));

        await requestStream.OnDisposedTask.DefaultTimeout();
    }
示例#28
0
        public async Task DATA_Sent_TooSlowlyDueToSocketBackPressureOnLargeWrite_AbortsConnectionAfterRateTimeout()
        {
            var mockSystemClock = _serviceContext.MockSystemClock;
            var limits          = _serviceContext.ServerOptions.Limits;

            // Use non-default value to ensure the min request and response rates aren't mixed up.
            limits.MinResponseDataRate = new MinDataRate(480, TimeSpan.FromSeconds(2.5));

            // Disable response buffering so "socket" backpressure is observed immediately.
            limits.MaxResponseBufferSize = 0;

            Http3Api._timeoutControl.Initialize(mockSystemClock.UtcNow.Ticks);

            var app           = new EchoAppWithNotification();
            var requestStream = await Http3Api.InitializeConnectionAndStreamsAsync(app.RunApp);

            await requestStream.SendHeadersAsync(_browserRequestHeaders, endStream : false);

            await requestStream.SendDataAsync(_maxData, endStream : true);

            await requestStream.ExpectHeadersAsync();

            await app.WriteStartedTask.DefaultTimeout();

            // Complete timing of the request body so we don't induce any unexpected request body rate timeouts.
            Http3Api._timeoutControl.Tick(mockSystemClock.UtcNow);

            var timeToWriteMaxData = TimeSpan.FromSeconds((requestStream.BytesReceived + _maxData.Length) / limits.MinResponseDataRate.BytesPerSecond) +
                                     limits.MinResponseDataRate.GracePeriod + Heartbeat.Interval - TimeSpan.FromSeconds(.5);

            // Don't read data frame to induce "socket" backpressure.
            Http3Api.AdvanceClock(timeToWriteMaxData);

            _mockTimeoutHandler.Verify(h => h.OnTimeout(It.IsAny <TimeoutReason>()), Times.Never);

            Http3Api.AdvanceClock(TimeSpan.FromSeconds(1));

            _mockTimeoutHandler.Verify(h => h.OnTimeout(TimeoutReason.WriteDataRate), Times.Once);

            // The _maxData bytes are buffered from before the timeout, but not an END_STREAM data frame.
            await requestStream.ExpectDataAsync();

            _mockTimeoutHandler.VerifyNoOtherCalls();
        }
示例#29
0
    public async Task HEADERS_CookiesMergedIntoOne()
    {
        var requestHeaders = new[]
        {
            new KeyValuePair <string, string>(HeaderNames.Method, "GET"),
            new KeyValuePair <string, string>(HeaderNames.Path, "/"),
            new KeyValuePair <string, string>(HeaderNames.Scheme, "http"),
            new KeyValuePair <string, string>(HeaderNames.Cookie, "a=0"),
            new KeyValuePair <string, string>(HeaderNames.Cookie, "b=1"),
            new KeyValuePair <string, string>(HeaderNames.Cookie, "c=2"),
        };

        var receivedHeaders = "";

        await Http3Api.InitializeConnectionAsync(async context =>
        {
            var buffer   = new byte[16 * 1024];
            var received = 0;

            // verify that the cookies are all merged into a single string
            receivedHeaders = context.Request.Headers[HeaderNames.Cookie];

            while ((received = await context.Request.Body.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                await context.Response.Body.WriteAsync(buffer, 0, received);
            }
        });

        await Http3Api.CreateControlStream();

        await Http3Api.GetInboundControlStream();

        var requestStream = await Http3Api.CreateRequestStream();

        await requestStream.SendHeadersAsync(requestHeaders, endStream : true);

        var responseHeaders = await requestStream.ExpectHeadersAsync();

        await requestStream.ExpectReceiveEndOfStream();

        await requestStream.OnDisposedTask.DefaultTimeout();

        Assert.Equal("a=0; b=1; c=2", receivedHeaders);
    }
示例#30
0
        public async Task SETTINGS_ReservedSettingSent_ConnectionError(long settingIdentifier)
        {
            await Http3Api.InitializeConnectionAsync(_echoApplication);

            var outboundcontrolStream = await Http3Api.CreateControlStream();

            await outboundcontrolStream.SendSettingsAsync(new List <Http3PeerSetting>
            {
                new Http3PeerSetting((Http3SettingType)settingIdentifier, 0)  // reserved value
            });

            await Http3Api.GetInboundControlStream();

            await Http3Api.WaitForConnectionErrorAsync <Http3ConnectionErrorException>(
                ignoreNonGoAwayFrames : true,
                expectedLastStreamId : 0,
                expectedErrorCode : Http3ErrorCode.SettingsError,
                expectedErrorMessage : CoreStrings.FormatHttp3ErrorControlStreamReservedSetting($"0x{settingIdentifier.ToString("X", CultureInfo.InvariantCulture)}"));
        }