XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;
using XFESystem.NativeRuntime.Application.Web;

namespace XFESystem.HttpProtocol.Tests;

public sealed class IndependentConnectionReuseTests
{
    [Theory]
    [InlineData("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK", true)]
    [InlineData("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n2\r\nOK\r\n0\r\n\r\n", true)]
    [InlineData("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: keep-alive, Close\r\n\r\nOK", false)]
    [InlineData("HTTP/1.0 200 OK\r\nContent-Length: 2\r\n\r\nOK", false)]
    [InlineData("HTTP/1.1 200 OK\r\n\r\nOK", false)]
    [InlineData("HTTP/1.1 302 Found\r\nLocation: /next\r\nContent-Length: 4\r\n\r\nmove", false)]
    [InlineData("HTTP/1.1 204 No Content\r\n\r\n", false)]
    [InlineData("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOKunsolicited", false)]
    public void OnlyFullyConsumedPersistentResponsesCanBeReused(string wire, bool reusable)
    {
        // Every possible boundary must preserve the actual HTTP body. Surplus
        // bytes only disqualify a wire when actually buffered by this reader.
        byte[] bytes = Encoding.UTF8.GetBytes(wire);
        for (int packet = 1; packet <= bytes.Length; packet++)
        {
            using var stream = new MemoryStream(bytes);
            var response = NativeHttpProtocol.ReadResponse((b, o, n) => stream.Read(b, o, Math.Min(n, packet)), 1024);
            if (!wire.EndsWith("unsolicited", StringComparison.Ordinal) || packet == bytes.Length)
                Assert.Equal(reusable, response.CanReuseConnection);
        }
    }

    [Fact]
    public void SameVerifiedOriginReusesWireAndInstallsTheNewAbsoluteDeadline()
    {
        var pool = new NativeHttpConnectionPool();
        int opens = 0, closes = 0; long installed = 0;
        var address = new Uri("https://example.test/a");
        NativeHttpConnectionPool.Connection Open() { opens++; return new(address, new MemoryStream(), d => installed = d, () => closes++, true, "TLS 1.3"); }
        var first = pool.Take(address, 10, 500, Open, out bool reused);
        Assert.False(reused); Assert.Equal(500, installed);
        pool.Return(first, true, 20);
        var second = pool.Take(new("https://EXAMPLE.test/b"), 30, 1000, Open, out reused);
        Assert.True(reused); Assert.Same(first, second); Assert.Equal(1000, installed);
        Assert.Equal(1, opens); Assert.Equal(0, closes);
        pool.Return(second, false, 40); Assert.Equal(1, closes);
    }

    [Theory]
    [InlineData("https://other.test/", 20, true)]
    [InlineData("http://example.test/", 20, true)]
    [InlineData("https://example.test:444/", 20, true)]
    [InlineData("https://example.test/", 10_011, true)]
    [InlineData("https://example.test/", 0, true)]
    [InlineData("https://example.test/", 20, false)]
    public void ChangedOriginExpiredClockOrUnverifiedTlsClosesBeforeOpening(string target, long now, bool verified)
    {
        var pool = new NativeHttpConnectionPool(); bool closed = false;
        var previous = new NativeHttpConnectionPool.Connection(new("https://example.test/"), new MemoryStream(), _ => { }, () => closed = true, verified, "TLS 1.2");
        pool.Return(previous, true, 10);
        var fresh = pool.Take(new(target), now, 20000, () =>
        { Assert.True(closed); return new(new(target), new MemoryStream(), _ => { }, () => { }, true, "TLS 1.3"); }, out bool reused);
        Assert.False(reused); Assert.NotSame(previous, fresh); pool.Return(fresh, false, now);
    }

    [Fact]
    public void ClosingAndFailedDeadlineSetupReleaseTheOwnerOnce()
    {
        var pool = new NativeHttpConnectionPool(); int closes = 0;
        var connection = new NativeHttpConnectionPool.Connection(new("http://example.test/"), new MemoryStream(), _ => throw new IOException("deadline"), () => closes++, false, "HTTP");
        Assert.Throws<IOException>(() => pool.Take(connection.Origin, 0, 20, () => connection, out _));
        connection.Close(); Assert.Equal(1, closes);
    }

    [Fact]
    public void IndependentParserStillRejectsAmbiguousOrTruncatedFraming()
    {
        foreach (string wire in new[] { "HTTP/1.1 200 OK\r\nContent-Length: 2\r\nTransfer-Encoding: chunked\r\n\r\nOK", "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nOK" })
        {
            using var stream = new MemoryStream(Encoding.ASCII.GetBytes(wire));
            Assert.Throws<IOException>(() => NativeHttpProtocol.ReadResponse(stream.Read, 1024));
        }
    }
}