HCR060¶
Dispose HttpResponseMessage when using ResponseHeadersRead.
Why¶
ResponseHeadersRead returns control before the response body has been fully consumed. The HttpResponseMessage remains the owner of the connection and content stream, so failing to dispose it can hold sockets and response resources longer than intended.
Bad¶
var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken);
Better¶
using var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken);
Returning a stream or content object from the response does not dispose the response owner:
var response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken);
return await response.Content.ReadAsStreamAsync(cancellationToken);
Suppression¶
Suppress only when ownership is transferred to the caller or another object that guarantees disposal.
Current Detection¶
The implementation reports local response variables initialized or assigned from awaited visible HttpClient calls such as SendAsync(...) or GetAsync(...), or synchronous HttpClient.Send(...), using HttpCompletionOption.ResponseHeadersRead unless the declaration is already a using var, owned by using (...) directly or through an order-preserving chain of unreassigned local aliases, transferred to a same-block using declaration such as using var owned = response, directly disposed at the containing block level through the same alias model, disposed in a finally block either directly or through those aliases, directly returned as the response, passed directly into a returned owner wrapper, assigned into a returned owner wrapper initializer, or transferred through a wrapper local that is returned. Parentheses, null-forgiving operators, and explicit response casts are treated as transparent around direct ownership references. Disposal, using-declaration transfer, and direct return evidence must apply before the response local is reassigned; disposing or returning a later assigned value does not count as ownership evidence for the original response. Conditional disposal such as if (...) response.Dispose(); is not treated as sufficient ownership evidence. Locals that only store the pending Task<HttpResponseMessage> are skipped so diagnostics target actual response owners. Resolved custom HttpClient types, unrelated custom extensions on HttpClient, custom lookalike HttpCompletionOption.ResponseHeadersRead members, and lookalike calls are skipped unless Roslyn type information shows that the receiver, method owner, completion option, and returned response shape are the System.Net.Http types, or the source is unresolved but visibly uses those framework names.
Code Fix¶
The code fix converts a simple local declaration into a using var declaration. It also merges an immediately adjacent uninitialized declaration and assignment into one using declaration, preserving comments between the two statements. Non-adjacent or nested assignments are left for manual ownership review.