Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public async Task Request_AcceptGzipDeflate_CompressedGzip()
{
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { "gzip", "deflate" }, responseType: TextPlain);

CheckResponseCompressed(response, expectedBodyLength: 29, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

Expand All @@ -68,7 +68,7 @@ public async Task Request_AcceptBrotli_CompressedBrotli()
{
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { "br" }, responseType: TextPlain);

CheckResponseCompressed(response, expectedBodyLength: 21, expectedEncoding: "br");
await CheckResponseCompressed(response, "br");
AssertCompressedWithLog(logMessages, "br");
}

Expand All @@ -79,7 +79,7 @@ public async Task Request_AcceptMixed_CompressedBrotli(string encoding1, string
{
var (response, logMessages) = await InvokeMiddleware(100, new[] { encoding1, encoding2 }, responseType: TextPlain);

CheckResponseCompressed(response, expectedBodyLength: 21, expectedEncoding: "br");
await CheckResponseCompressed(response, "br");
AssertCompressedWithLog(logMessages, "br");
}

Expand All @@ -96,7 +96,7 @@ void Configure(ResponseCompressionOptions options)

var (response, logMessages) = await InvokeMiddleware(100, new[] { encoding1, encoding2 }, responseType: TextPlain, configure: Configure);

CheckResponseCompressed(response, expectedBodyLength: 29, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

Expand Down Expand Up @@ -127,7 +127,7 @@ public async Task RequestHead_AcceptGzipDeflate_CompressedGzip()
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { "gzip", "deflate" }, responseType: TextPlain, httpMethod: HttpMethods.Head);

// Per RFC 7231, section 4.3.2, the Content-Length header can be omitted on HEAD requests.
CheckResponseCompressed(response, expectedBodyLength: null, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

Expand All @@ -140,7 +140,7 @@ public async Task ContentType_WithCharset_Compress(string contentType)
{
var (response, logMessages) = await InvokeMiddleware(uncompressedBodyLength: 100, requestAcceptEncodings: new[] { "gzip" }, contentType);

CheckResponseCompressed(response, expectedBodyLength: 29, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

Expand Down Expand Up @@ -179,7 +179,7 @@ public async Task GZipCompressionProvider_OptionsSetInDI_Compress()

var response = await client.SendAsync(request);

CheckResponseCompressed(response, expectedBodyLength: 133, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
}

[Theory]
Expand Down Expand Up @@ -272,7 +272,7 @@ bool compress

if (compress)
{
CheckResponseCompressed(response, expectedBodyLength: 29, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}
else
Expand All @@ -293,7 +293,7 @@ public async Task NoIncludedMimeTypes_UseDefaults()
options.ExcludedMimeTypes = new[] { "text/*" };
});

CheckResponseCompressed(response, expectedBodyLength: 29, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

Expand Down Expand Up @@ -345,7 +345,7 @@ public async Task Request_AcceptStar_Compressed()
{
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { "*" }, responseType: TextPlain);

CheckResponseCompressed(response, expectedBodyLength: 21, expectedEncoding: "br");
await CheckResponseCompressed(response, "br");
AssertCompressedWithLog(logMessages, "br");
}

Expand All @@ -362,24 +362,24 @@ public async Task Request_AcceptIdentity_NotCompressed()
}

[Theory]
[InlineData(new[] { "identity;q=0.5", "gzip;q=1" }, 29)]
[InlineData(new[] { "identity;q=0", "gzip;q=0.8" }, 29)]
[InlineData(new[] { "identity;q=0.5", "gzip" }, 29)]
public async Task Request_AcceptWithHigherCompressionQuality_Compressed(string[] acceptEncodings, int expectedBodyLength)
[InlineData("identity;q=0.5", "gzip;q=1")]
[InlineData("identity;q=0", "gzip;q=0.8")]
[InlineData("identity;q=0.5", "gzip")]
public async Task Request_AcceptWithHigherCompressionQuality_Compressed(string encoding1, string encoding2)
{
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain);
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { encoding1, encoding2 }, responseType: TextPlain);

CheckResponseCompressed(response, expectedBodyLength: expectedBodyLength, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");
AssertCompressedWithLog(logMessages, "gzip");
}

[Theory]
[InlineData(new[] { "gzip;q=0.5", "identity;q=0.8" }, 100)]
public async Task Request_AcceptWithhigherIdentityQuality_NotCompressed(string[] acceptEncodings, int expectedBodyLength)
[InlineData("gzip;q=0.5", "identity;q=0.8")]
public async Task Request_AcceptWithhigherIdentityQuality_NotCompressed(string encoding1, string encoding2)
{
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: acceptEncodings, responseType: TextPlain);
var (response, logMessages) = await InvokeMiddleware(100, requestAcceptEncodings: new[] { encoding1, encoding2 }, responseType: TextPlain);

CheckResponseNotCompressed(response, expectedBodyLength: expectedBodyLength, sendVaryHeader: true);
CheckResponseNotCompressed(response, expectedBodyLength: 100, sendVaryHeader: true);
Assert.Equal(3, logMessages.Count);
AssertLog(logMessages.First(), LogLevel.Trace, "This request accepts compression.");
AssertLog(logMessages.Skip(1).First(), LogLevel.Trace, "Response compression is available for this Content-Type.");
Expand Down Expand Up @@ -476,7 +476,14 @@ public async Task Request_Https_CompressedIfEnabled(bool enableHttps, int expect

var response = await client.SendAsync(request);

Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
if (enableHttps)
{
await CheckResponseCompressed(response, "gzip");
}
else
{
Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
}

var logMessages = sink.Writes.ToList();
if (enableHttps)
Expand Down Expand Up @@ -539,7 +546,14 @@ public async Task Request_Https_CompressedIfOptIn(HttpsCompressionMode mode, int

var response = await client.SendAsync(request);

Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
if (mode == HttpsCompressionMode.Compress)
{
await CheckResponseCompressed(response, "gzip");
}
else
{
Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
}

var logMessages = sink.Writes.ToList();
if (mode == HttpsCompressionMode.Compress)
Expand Down Expand Up @@ -602,7 +616,14 @@ public async Task Request_Https_NotCompressedIfOptOut(HttpsCompressionMode mode,

var response = await client.SendAsync(request);

Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
if (mode != HttpsCompressionMode.DoNotCompress)
{
await CheckResponseCompressed(response, "gzip");
}
else
{
Assert.Equal(expectedLength, (await response.Content.ReadAsByteArrayAsync()).Length);
}

var logMessages = sink.Writes.ToList();
if (mode == HttpsCompressionMode.DoNotCompress)
Expand All @@ -616,8 +637,8 @@ public async Task Request_Https_NotCompressedIfOptOut(HttpsCompressionMode mode,
}

[Theory]
[MemberData(nameof(SupportedEncodingsWithBodyLength))]
public async Task FlushHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength)
[MemberData(nameof(SupportedEncodings))]
public async Task FlushHeaders_SendsHeaders_Compresses(string encoding)
{
var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

Expand Down Expand Up @@ -658,12 +679,12 @@ public async Task FlushHeaders_SendsHeaders_Compresses(string encoding, int expe

await response.Content.LoadIntoBufferAsync();

CheckResponseCompressed(response, expectedBodyLength, encoding);
await CheckResponseCompressed(response, encoding);
}

[Theory]
[MemberData(nameof(SupportedEncodingsWithBodyLength))]
public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding, int expectedBodyLength)
[MemberData(nameof(SupportedEncodings))]
public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding)
{
var responseReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

Expand Down Expand Up @@ -703,7 +724,7 @@ public async Task FlushAsyncHeaders_SendsHeaders_Compresses(string encoding, int

await response.Content.LoadIntoBufferAsync();

CheckResponseCompressed(response, expectedBodyLength, encoding);
await CheckResponseCompressed(response, encoding);
}

[Theory]
Expand Down Expand Up @@ -1114,7 +1135,7 @@ public async Task SendFileAsync_FirstWrite_CompressesAndFlushes()

var response = await client.SendAsync(request);

CheckResponseCompressed(response, expectedBodyLength: 35, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");

Assert.False(fakeSendFile.SendFileInvoked);
}
Expand Down Expand Up @@ -1164,7 +1185,7 @@ public async Task SendFileAsync_AfterFirstWrite_CompressesAndFlushes()

var response = await client.SendAsync(request);

CheckResponseCompressed(response, expectedBodyLength: 46, expectedEncoding: "gzip");
await CheckResponseCompressed(response, "gzip");

Assert.False(fakeSendFile.SendFileInvoked);
}
Expand Down Expand Up @@ -1286,7 +1307,7 @@ public async Task Dispose_SyncWriteOrFlushNotCalled(string encoding)
return (response, sink.Writes.ToList());
}

private static void CheckResponseCompressed(HttpResponseMessage response, long? expectedBodyLength, string expectedEncoding)
private static async Task CheckResponseCompressed(HttpResponseMessage response, string expectedEncoding)
{
var containsVaryAcceptEncoding = false;
foreach (var value in response.Headers.GetValues(HeaderNames.Vary))
Expand All @@ -1300,7 +1321,53 @@ private static void CheckResponseCompressed(HttpResponseMessage response, long?
Assert.True(containsVaryAcceptEncoding);
Assert.False(response.Content.Headers.TryGetValues(HeaderNames.ContentMD5, out _));
Assert.Single(response.Content.Headers.ContentEncoding, expectedEncoding);
Assert.Equal(expectedBodyLength, response.Content.Headers.ContentLength);

// Test functionality instead of exact byte counts
await CheckCompressionFunctionality(response, expectedEncoding, new string('a', 100));
}

private static async Task CheckCompressionFunctionality(HttpResponseMessage response, string expectedEncoding, string expectedContent)
{
var compressedBytes = await response.Content.ReadAsByteArrayAsync();

// Handle HEAD requests - no body to decompress
if (response.RequestMessage?.Method == HttpMethod.Head)
{
return;
}

// Decompress and verify content matches original
string decompressedContent;

if (expectedEncoding == "gzip")
{
using var compressedStream = new MemoryStream(compressedBytes);
using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress);
using var reader = new StreamReader(gzipStream);
decompressedContent = await reader.ReadToEndAsync();
}
else if (expectedEncoding == "br")
{
using var compressedStream = new MemoryStream(compressedBytes);
using var brotliStream = new BrotliStream(compressedStream, CompressionMode.Decompress);
using var reader = new StreamReader(brotliStream);
decompressedContent = await reader.ReadToEndAsync();
}
else
{
throw new ArgumentException($"Unsupported encoding: {expectedEncoding}");
}

// Verify decompressed content matches what we expect
if (decompressedContent.Length >= expectedContent.Length && decompressedContent.StartsWith(expectedContent, StringComparison.Ordinal))
{
// Handles cases like SendFileAsync where additional content is appended
Assert.True(true);
}
else
{
Assert.Equal(expectedContent, decompressedContent);
}
}

private static void CheckResponseNotCompressed(HttpResponseMessage response, long? expectedBodyLength, bool sendVaryHeader)
Expand Down
Loading