using System.Text;
using XFESystem.NativeRuntime.Application.Web;
namespace XFESystem.Browser.Tests;
public sealed class IndependentHttpEvidenceTests
{
private static NativeHttpResponse Read(string wire, int maximum = 4096)
{
byte[] bytes = Encoding.UTF8.GetBytes(wire); int position = 0;
return NativeHttpProtocol.ReadResponse((buffer, offset, count) =>
{
int copied = Math.Min(Math.Min(count, 3), bytes.Length - position);
bytes.AsSpan(position, copied).CopyTo(buffer.AsSpan(offset)); position += copied; return copied;
}, maximum);
}
[Fact]
public void RealFragmentedHeadersAndChunkedUtf8BodyRetainTheirEvidence()
{
var response = Read("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nTransfer-Encoding: chunked\r\nX-Origin: fixture\r\n\r\n3\r\n中\r\n3\r\n文\r\n0\r\n\r\n");
Assert.Equal("中文", NativeHttpProtocol.DecodeBody(response));
Assert.Equal("HTTP/1.1 200 OK", response.StatusLine);
Assert.Equal("fixture", response.Headers["x-origin"]);
Assert.Equal(6, response.Body.Length);
}
[Theory]
[InlineData("Content-Length: 1\r\nTransfer-Encoding: chunked\r\n")]
[InlineData("Content-Length: 1\r\nContent-Length: 1\r\n")]
[InlineData("Transfer-Encoding: gzip, chunked\r\n")]
public void AmbiguousOrUnsupportedFramingNeverBecomesSuccessfulPageEvidence(string headers)
{ Assert.ThrowsAny<Exception>(() => Read("HTTP/1.1 200 OK\r\n" + headers + "\r\nx")); }
[Fact]
public void TruncatedAndOversizedBodiesAreRejected()
{
Assert.Throws<IOException>(() => Read("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nx"));
Assert.Throws<BrowserLimitException>(() => Read("HTTP/1.1 200 OK\r\nContent-Length: 20\r\n\r\n", 10));
}
[Fact]
public void RedirectEvidenceRetainsActualStatusAndLocation()
{
var response = Read("HTTP/1.1 302 Found\r\nLocation: https://other.example/\r\nContent-Length: 0\r\n\r\n");
Assert.Equal(302, response.StatusCode); Assert.Equal("https://other.example/", response.Location);
Assert.Equal("HTTP/1.1 302 Found", response.StatusLine); Assert.Empty(response.Body);
}
}
using System.Text;
using XFESystem.NativeRuntime.Application.Web;
namespace XFESystem.Browser.Tests;
public sealed class IndependentHttpEvidenceTests
{
private static NativeHttpResponse Read(string wire, int maximum = 4096)
{
byte[] bytes = Encoding.UTF8.GetBytes(wire); int position = 0;
return NativeHttpProtocol.ReadResponse((buffer, offset, count) =>
{
int copied = Math.Min(Math.Min(count, 3), bytes.Length - position);
bytes.AsSpan(position, copied).CopyTo(buffer.AsSpan(offset)); position += copied; return copied;
}, maximum);
}
[Fact]
public void RealFragmentedHeadersAndChunkedUtf8BodyRetainTheirEvidence()
{
var response = Read("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nTransfer-Encoding: chunked\r\nX-Origin: fixture\r\n\r\n3\r\n中\r\n3\r\n文\r\n0\r\n\r\n");
Assert.Equal("中文", NativeHttpProtocol.DecodeBody(response));
Assert.Equal("HTTP/1.1 200 OK", response.StatusLine);
Assert.Equal("fixture", response.Headers["x-origin"]);
Assert.Equal(6, response.Body.Length);
}
[Theory]
[InlineData("Content-Length: 1\r\nTransfer-Encoding: chunked\r\n")]
[InlineData("Content-Length: 1\r\nContent-Length: 1\r\n")]
[InlineData("Transfer-Encoding: gzip, chunked\r\n")]
public void AmbiguousOrUnsupportedFramingNeverBecomesSuccessfulPageEvidence(string headers)
{ Assert.ThrowsAny<Exception>(() => Read("HTTP/1.1 200 OK\r\n" + headers + "\r\nx")); }
[Fact]
public void TruncatedAndOversizedBodiesAreRejected()
{
Assert.Throws<IOException>(() => Read("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nx"));
Assert.Throws<BrowserLimitException>(() => Read("HTTP/1.1 200 OK\r\nContent-Length: 20\r\n\r\n", 10));
}
[Fact]
public void RedirectEvidenceRetainsActualStatusAndLocation()
{
var response = Read("HTTP/1.1 302 Found\r\nLocation: https://other.example/\r\nContent-Length: 0\r\n\r\n");
Assert.Equal(302, response.StatusCode); Assert.Equal("https://other.example/", response.Location);
Assert.Equal("HTTP/1.1 302 Found", response.StatusLine); Assert.Empty(response.Body);
}
}