Skip to content

Commit 9d9cbea

Browse files
committed
Fix bug
1 parent eee015a commit 9d9cbea

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

src/StaticWebAssetsSdk/Tasks/ApplyCompressionNegotiation.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ApplyCompressionNegotiation : Task
2222

2323
private readonly List<StaticWebAssetEndpointSelector> _selectorsList = new();
2424
private readonly List<StaticWebAssetEndpointResponseHeader> _headersList = new();
25+
private readonly List<StaticWebAssetEndpointResponseHeader> _tempHeadersList = new();
2526
private readonly List<StaticWebAssetEndpointProperty> _propertiesList = new();
2627
private const int ExpectedCompressionHeadersCount = 2;
2728

@@ -326,9 +327,9 @@ private static StaticWebAssetEndpointProperty ResolveFingerprint(StaticWebAssetE
326327

327328
private void ApplyCompressedEndpointHeaders(List<StaticWebAssetEndpointResponseHeader> headers, StaticWebAssetEndpoint compressedEndpoint, string relatedEndpointCandidateRoute)
328329
{
329-
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(compressedEndpoint.ResponseHeadersString, _headersList);
330+
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(compressedEndpoint.ResponseHeadersString, _tempHeadersList);
330331

331-
foreach (var header in _headersList)
332+
foreach (var header in _tempHeadersList)
332333
{
333334
if (string.Equals(header.Name, "Content-Type", StringComparison.Ordinal))
334335
{
@@ -346,9 +347,9 @@ private void ApplyCompressedEndpointHeaders(List<StaticWebAssetEndpointResponseH
346347

347348
private void ApplyRelatedEndpointCandidateHeaders(List<StaticWebAssetEndpointResponseHeader> headers, StaticWebAssetEndpoint relatedEndpointCandidate, HashSet<string> compressedHeaders)
348349
{
349-
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(relatedEndpointCandidate.ResponseHeadersString, _headersList);
350+
StaticWebAssetEndpointResponseHeader.PopulateFromMetadataValue(relatedEndpointCandidate.ResponseHeadersString, _tempHeadersList);
350351

351-
foreach (var header in _headersList)
352+
foreach (var header in _tempHeadersList)
352353
{
353354
// We need to keep the headers that are specific to the compressed asset like Content-Length,
354355
// Last-Modified and ETag. Any other header we should add it.

test/Microsoft.NET.Sdk.StaticWebAssets.Tests/StaticWebAssets/ApplyCompressionNegotiationTest.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,65 @@ public void AppliesContentNegotiationRules_ToAllRelatedAssetEndpoints()
930930
]);
931931
}
932932

933+
[Fact]
934+
public void AppliesContentNegotiationRules_DoesNotFailWithCollectionModifiedException()
935+
{
936+
// This test reproduces the bug where shared lists were being modified during enumeration
937+
var errorMessages = new List<string>();
938+
var buildEngine = new Mock<IBuildEngine>();
939+
buildEngine.Setup(e => e.LogErrorEvent(It.IsAny<BuildErrorEventArgs>()))
940+
.Callback<BuildErrorEventArgs>(args => errorMessages.Add(args.Message));
941+
942+
var task = new ApplyCompressionNegotiation
943+
{
944+
BuildEngine = buildEngine.Object,
945+
CandidateAssets =
946+
[
947+
CreateCandidate(
948+
Path.Combine("wwwroot", "candidate.js"),
949+
"MyPackage",
950+
"Discovered",
951+
"candidate.js",
952+
"All",
953+
"All",
954+
"original-fingerprint",
955+
"original",
956+
fileLength: 20
957+
),
958+
CreateCandidate(
959+
Path.Combine("compressed", "candidate.js.gz"),
960+
"MyPackage",
961+
"Discovered",
962+
"candidate.js",
963+
"All",
964+
"All",
965+
"compressed-fingerprint",
966+
"compressed",
967+
Path.Combine("wwwroot", "candidate.js"),
968+
"Content-Encoding",
969+
"gzip",
970+
9
971+
)
972+
],
973+
CandidateEndpoints =
974+
[
975+
CreateCandidateEndpoint(
976+
"candidate.js",
977+
Path.Combine("wwwroot", "candidate.js"),
978+
CreateHeaders("text/javascript", [("Content-Length", "20"), ("Cache-Control", "max-age=3600"), ("ETag", "\"original-etag\""), ("Last-Modified", "Wed, 01 Jan 2020 00:00:00 GMT")])),
979+
980+
CreateCandidateEndpoint(
981+
"candidate.js.gz",
982+
Path.Combine("compressed", "candidate.js.gz"),
983+
CreateHeaders("text/javascript", [("Content-Length", "9"), ("Cache-Control", "max-age=3600"), ("ETag", "\"compressed-etag\""), ("Last-Modified", "Wed, 01 Jan 2020 00:00:00 GMT")]))
984+
],
985+
};
986+
987+
// Act & Assert - This should not throw a CollectionModifiedException
988+
var result = task.Execute();
989+
result.Should().Be(true);
990+
}
991+
933992
[Fact]
934993
public void AppliesContentNegotiationRules_IgnoresAlreadyProcessedEndpoints()
935994
{

0 commit comments

Comments
 (0)