Fix TransferEncodingChunked returning true after being set to false#122409
Fix TransferEncodingChunked returning true after being set to false#122409stephentoub merged 8 commits intomainfrom
Conversation
…false Co-authored-by: stephentoub <[email protected]>
Co-authored-by: stephentoub <[email protected]>
|
Tagging subscribers to this area: @dotnet/ncl |
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug in HttpGeneralHeaders.TransferEncodingChunked where the setter only removed the first "chunked" value when set to false, even though multiple "chunked" values could exist. The getter returns true if any "chunked" value exists, creating an inconsistency where setting the property to false could leave it returning true.
Key changes:
- Modified the
TransferEncodingChunkedsetter to loopRemoveParsedValueuntil all "chunked" values are removed - Added test
TransferEncodingChunked_SetToFalse_RemovesAllChunkedValuesto validate the fix - Updated test
Add_UseSpecialValueWithSpecialAlreadyPresent_AddsDuplicateto reflect corrected behavior where all duplicates are removed
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpGeneralHeaders.cs | Changed TransferEncodingChunked setter to use a while loop that calls RemoveParsedValue repeatedly until all "chunked" values are removed |
| src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpRequestHeadersTest.cs | Added new test verifying that setting TransferEncodingChunked to false removes all "chunked" values when multiple are present |
| src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeaderValueCollectionTest.cs | Updated existing test expectations to reflect that setting TransferEncodingChunked to false now correctly removes all "chunked" values |
|
@copilot Since |
…e pass Co-authored-by: MihaZupan <[email protected]>
Optimized to remove all matching values in a single O(n) pass. Added new internal |
…tation Co-authored-by: MihaZupan <[email protected]>
|
@copilot That duplicates all the removal logic. Can you make |
Co-authored-by: MihaZupan <[email protected]>
Refactored to add |
|
@copilot That approach is still quadratic since An alternative could be to do something like replacing the existing loop with for (int i = 0; i < parsedValues.Count; i++)
{
object item = parsedValues[i];
if (item is not InvalidValue)
{
Debug.Assert(item.GetType() == value.GetType(),
"One of the stored values does not have the same type as 'value'.");
if (AreEqual(value, item, comparer))
{
parsedValues.RemoveAt(i);
i--;
if (!result)
{
result = true;
if (!removeAll)
{
break;
}
}
else
{
// We've removed a second item. Fallback to RemoveAll in case there are more to maintain a linear worst-case.
// Create a copy of the locals to avoid the capture allocation in the common case.
object valueLocal = value;
IEqualityComparer? comparerLocal = comparer;
parsedValues.RemoveAll(i => AreEqual(valueLocal, i, comparerLocal);
break;
}
}
}
} |
Co-authored-by: MihaZupan <[email protected]>
Implemented the suggested optimization. The code now removes the first match with |
src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpRequestHeadersTest.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: MihaZupan <[email protected]>
Fixes Issue
main PR
Description
TransferEncodingChunkedsetter only removed the first "chunked" value while the getter returns true if any "chunked" exists. Setting the property to false with multiple "chunked" values left the property returning true.Changes:
removeAllparameter (defaultfalse) to existingRemoveParsedValuemethod inHttpHeaders.csremoveAllistrue, uses an optimized removal strategy: removes first match withRemoveAt, then falls back toList.RemoveAllfor remaining matches to maintain O(n) complexityremoveAllisfalse, maintains original behavior (removes first match only)HttpGeneralHeaders.TransferEncodingChunkedsetter to callRemoveParsedValuewithremoveAll: trueRemoveParsedValuemethodTransferEncodingChunked_SetToFalse_RemovesAllChunkedValuesthat validates removal of all "chunked" values while preserving other transfer-encoding valuesAdd_UseSpecialValueWithSpecialAlreadyPresent_AddsDuplicateto reflect corrected behaviorPerformance:
The optimized approach maintains O(n) worst-case complexity:
List.RemoveAll(single pass) for remaining itemsCustomer Impact
Applications adding multiple "chunked" transfer-encoding values cannot reliably disable chunked encoding. Setting
TransferEncodingChunked = falsefails silently, causing incorrect HTTP headers.Regression
No. This is a pre-existing bug where
RemoveParsedValueonly removes the first matching item.Testing
All 2,666 System.Net.Http unit tests pass. New test validates removing multiple "chunked" values while preserving other transfer-encoding values (e.g., "abc" and "def").
Risk
Low. Change is isolated to
TransferEncodingChunkedsetter and adds an optional parameter to existingRemoveParsedValuemethod. The parameter maintains backward compatibility with default valuefalse. When set totrue, efficiently removes all matching values while maintaining O(n) complexity. Existing single "chunked" value cases unchanged.Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.