SocketsHttpHandlerTest.Http1KeepAlive.cs 5.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net.Test.Common;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace System.Net.Http.Functional.Tests
{
    [ConditionalClass(typeof(SocketsHttpHandler), nameof(SocketsHttpHandler.IsSupported))]
    public sealed class SocketsHttpHandler_Http1KeepAlive_Test : HttpClientHandlerTestBase
    {
        public SocketsHttpHandler_Http1KeepAlive_Test(ITestOutputHelper output) : base(output) { }

        [Fact]
        public async Task Http10Response_ConnectionIsReusedFor10And11()
        {
            await LoopbackServer.CreateClientAndServerAsync(async uri =>
            {
                using HttpClient client = CreateHttpClient();

                await client.SendAsync(CreateRequest(HttpMethod.Get, uri, HttpVersion.Version10, exactVersion: true));
                await client.SendAsync(CreateRequest(HttpMethod.Get, uri, HttpVersion.Version11, exactVersion: true));
                await client.SendAsync(CreateRequest(HttpMethod.Get, uri, HttpVersion.Version10, exactVersion: true));
            },
            server => server.AcceptConnectionAsync(async connection =>
            {
                HttpRequestData request = await connection.ReadRequestDataAsync();
                Assert.Equal(0, request.Version.Minor);
                await connection.WriteStringAsync("HTTP/1.0 200 OK\r\nContent-Length: 1\r\n\r\n1");
                connection.CompleteRequestProcessing();

                request = await connection.ReadRequestDataAsync();
                Assert.Equal(1, request.Version.Minor);
                await connection.WriteStringAsync("HTTP/1.0 200 OK\r\nContent-Length: 1\r\n\r\n2");
                connection.CompleteRequestProcessing();

                request = await connection.ReadRequestDataAsync();
                Assert.Equal(0, request.Version.Minor);
                await connection.WriteStringAsync("HTTP/1.0 200 OK\r\nContent-Length: 1\r\n\r\n3");
            }));
        }

        [OuterLoop("Uses Task.Delay")]
        [Fact]
47
        public async Task Http1ResponseWithKeepAliveTimeout_ConnectionRecycledAfterTimeout()
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
        {
            await LoopbackServer.CreateClientAndServerAsync(async uri =>
            {
                using HttpClient client = CreateHttpClient();

                await client.GetAsync(uri);

                await Task.Delay(2000);
                await client.GetAsync(uri);
            },
            async server =>
            {
                await server.AcceptConnectionAsync(async connection =>
                {
                    await connection.ReadRequestDataAsync();
63
                    await connection.WriteStringAsync("HTTP/1.1 200 OK\r\nKeep-Alive: timeout=2\r\nContent-Length: 1\r\n\r\n1");
64 65 66 67 68 69 70 71 72 73 74 75 76
                    connection.CompleteRequestProcessing();

                    await Assert.ThrowsAnyAsync<Exception>(() => connection.ReadRequestDataAsync());
                });

                await server.AcceptConnectionSendResponseAndCloseAsync();
            });
        }

        [Theory]
        [InlineData("timeout=1000", true)]
        [InlineData("timeout=30", true)]
        [InlineData("timeout=0", false)]
77
        [InlineData("timeout=1", false)]
78 79 80 81 82 83 84 85 86 87 88 89
        [InlineData("foo, bar=baz, timeout=30", true)]
        [InlineData("foo, bar=baz, timeout=0", false)]
        [InlineData("timeout=-1", true)]
        [InlineData("timeout=abc", true)]
        [InlineData("max=1", true)]
        [InlineData("max=0", false)]
        [InlineData("max=-1", true)]
        [InlineData("max=abc", true)]
        [InlineData("timeout=30, max=1", true)]
        [InlineData("timeout=30, max=0", false)]
        [InlineData("timeout=0, max=1", false)]
        [InlineData("timeout=0, max=0", false)]
90
        public async Task Http1ResponseWithKeepAlive_ConnectionNotReusedForShortTimeoutOrMax0(string keepAlive, bool shouldReuseConnection)
91 92 93 94 95 96 97 98 99 100 101 102 103
        {
            await LoopbackServer.CreateClientAndServerAsync(async uri =>
            {
                using HttpClient client = CreateHttpClient();

                await client.GetAsync(uri);
                await client.GetAsync(uri);
            },
            async server =>
            {
                await server.AcceptConnectionAsync(async connection =>
                {
                    await connection.ReadRequestDataAsync();
104
                    await connection.WriteStringAsync($"HTTP/1.{Random.Shared.Next(10)} 200 OK\r\nKeep-Alive: {keepAlive}\r\nContent-Length: 1\r\n\r\n1");
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
                    connection.CompleteRequestProcessing();

                    if (shouldReuseConnection)
                    {
                        await connection.HandleRequestAsync();
                    }
                    else
                    {
                        await Assert.ThrowsAnyAsync<Exception>(() => connection.ReadRequestDataAsync());
                    }
                });

                if (!shouldReuseConnection)
                {
                    await server.AcceptConnectionSendResponseAndCloseAsync();
                }
            });
        }
    }
}