|
1 | 1 | // Licensed to the .NET Foundation under one or more agreements.
|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 |
|
4 |
| -using System; |
5 |
| -using System.Collections.Generic; |
6 |
| -using System.Linq; |
7 | 4 | using System.Net.Http;
|
8 |
| -using System.Reflection.PortableExecutable; |
9 |
| -using System.Threading.Tasks; |
10 | 5 | using Microsoft.AspNetCore.Connections;
|
11 | 6 | using Microsoft.AspNetCore.Http;
|
12 | 7 | using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
13 |
| -using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3; |
14 | 8 | using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
15 | 9 | using Microsoft.AspNetCore.Testing;
|
16 | 10 | using Microsoft.Extensions.Logging;
|
17 | 11 | using Moq;
|
18 |
| -using Xunit; |
19 |
| -using Xunit.Sdk; |
20 | 12 |
|
21 | 13 | namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests;
|
22 | 14 |
|
23 | 15 | public class Http3TimeoutTests : Http3TestBase
|
24 | 16 | {
|
| 17 | + [Fact] |
| 18 | + public async Task KeepAliveTimeout_ControlStreamNotReceived_ConnectionClosed() |
| 19 | + { |
| 20 | + var limits = _serviceContext.ServerOptions.Limits; |
| 21 | + |
| 22 | + await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout(); |
| 23 | + |
| 24 | + var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout(); |
| 25 | + await controlStream.ExpectSettingsAsync().DefaultTimeout(); |
| 26 | + |
| 27 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout + TimeSpan.FromTicks(1)); |
| 28 | + |
| 29 | + await Http3Api.WaitForConnectionStopAsync(0, false, expectedErrorCode: Http3ErrorCode.NoError); |
| 30 | + } |
| 31 | + |
| 32 | + [Fact] |
| 33 | + public async Task KeepAliveTimeout_RequestNotReceived_ConnectionClosed() |
| 34 | + { |
| 35 | + var limits = _serviceContext.ServerOptions.Limits; |
| 36 | + |
| 37 | + await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout(); |
| 38 | + await Http3Api.CreateControlStream(); |
| 39 | + |
| 40 | + var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout(); |
| 41 | + await controlStream.ExpectSettingsAsync().DefaultTimeout(); |
| 42 | + |
| 43 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout + TimeSpan.FromTicks(1)); |
| 44 | + |
| 45 | + await Http3Api.WaitForConnectionStopAsync(0, false, expectedErrorCode: Http3ErrorCode.NoError); |
| 46 | + } |
| 47 | + |
| 48 | + [Fact] |
| 49 | + public async Task KeepAliveTimeout_AfterRequestComplete_ConnectionClosed() |
| 50 | + { |
| 51 | + var requestHeaders = new[] |
| 52 | + { |
| 53 | + new KeyValuePair<string, string>(InternalHeaderNames.Method, "GET"), |
| 54 | + new KeyValuePair<string, string>(InternalHeaderNames.Path, "/"), |
| 55 | + new KeyValuePair<string, string>(InternalHeaderNames.Scheme, "http"), |
| 56 | + }; |
| 57 | + |
| 58 | + var limits = _serviceContext.ServerOptions.Limits; |
| 59 | + |
| 60 | + await Http3Api.InitializeConnectionAsync(_noopApplication).DefaultTimeout(); |
| 61 | + |
| 62 | + await Http3Api.CreateControlStream(); |
| 63 | + var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout(); |
| 64 | + await controlStream.ExpectSettingsAsync().DefaultTimeout(); |
| 65 | + var requestStream = await Http3Api.CreateRequestStream(requestHeaders, endStream: true); |
| 66 | + await requestStream.ExpectHeadersAsync(); |
| 67 | + |
| 68 | + await requestStream.ExpectReceiveEndOfStream(); |
| 69 | + await requestStream.OnDisposedTask.DefaultTimeout(); |
| 70 | + |
| 71 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1)); |
| 72 | + |
| 73 | + await Http3Api.WaitForConnectionStopAsync(4, false, expectedErrorCode: Http3ErrorCode.NoError); |
| 74 | + } |
| 75 | + |
| 76 | + [Fact] |
| 77 | + public async Task KeepAliveTimeout_LongRunningRequest_KeepsConnectionAlive() |
| 78 | + { |
| 79 | + var requestHeaders = new[] |
| 80 | + { |
| 81 | + new KeyValuePair<string, string>(InternalHeaderNames.Method, "GET"), |
| 82 | + new KeyValuePair<string, string>(InternalHeaderNames.Path, "/"), |
| 83 | + new KeyValuePair<string, string>(InternalHeaderNames.Scheme, "http"), |
| 84 | + }; |
| 85 | + |
| 86 | + var limits = _serviceContext.ServerOptions.Limits; |
| 87 | + var requestReceivedTcs = new TaskCompletionSource(); |
| 88 | + var requestFinishedTcs = new TaskCompletionSource(); |
| 89 | + |
| 90 | + await Http3Api.InitializeConnectionAsync(_ => |
| 91 | + { |
| 92 | + requestReceivedTcs.SetResult(); |
| 93 | + return requestFinishedTcs.Task; |
| 94 | + }).DefaultTimeout(); |
| 95 | + |
| 96 | + await Http3Api.CreateControlStream(); |
| 97 | + var controlStream = await Http3Api.GetInboundControlStream().DefaultTimeout(); |
| 98 | + await controlStream.ExpectSettingsAsync().DefaultTimeout(); |
| 99 | + var requestStream = await Http3Api.CreateRequestStream(requestHeaders, endStream: true); |
| 100 | + |
| 101 | + await requestReceivedTcs.Task; |
| 102 | + |
| 103 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout); |
| 104 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout); |
| 105 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout); |
| 106 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout); |
| 107 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout); |
| 108 | + |
| 109 | + requestFinishedTcs.SetResult(); |
| 110 | + |
| 111 | + await requestStream.ExpectHeadersAsync(); |
| 112 | + |
| 113 | + await requestStream.ExpectReceiveEndOfStream(); |
| 114 | + await requestStream.OnDisposedTask.DefaultTimeout(); |
| 115 | + |
| 116 | + Http3Api.AdvanceClock(limits.KeepAliveTimeout + Heartbeat.Interval + TimeSpan.FromTicks(1)); |
| 117 | + |
| 118 | + await Http3Api.WaitForConnectionStopAsync(4, false, expectedErrorCode: Http3ErrorCode.NoError); |
| 119 | + } |
25 | 120 |
|
26 | 121 | [Fact]
|
27 | 122 | public async Task HEADERS_IncompleteFrameReceivedWithinRequestHeadersTimeout_StreamError()
|
|
0 commit comments