Skip to content

Commit

Permalink
Reduce the size of HttpRequestMessage and HttpRequestHeaders (#81251)
Browse files Browse the repository at this point in the history
* Reduce the size of HttpRequestMessage and HttpRequestHeaders

* Assert that the request message can't transition from Disposed to non-Disposed
  • Loading branch information
MihaZupan committed Jan 27, 2023
1 parent d8d88da commit 5971947
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public sealed class HttpRequestHeaders : HttpHeaders
private const int IfNoneMatchSlot = 5;
private const int TransferEncodingSlot = 6;
private const int UserAgentSlot = 7;
private const int NumCollectionsSlots = 8;
private const int ExpectSlot = 8;
private const int ProtocolSlot = 9;
private const int NumCollectionsSlots = 10;

private object[]? _specialCollectionsSlots;
private object?[]? _specialCollectionsSlots;
private HttpGeneralHeaders? _generalHeaders;
private HttpHeaderValueCollection<NameValueWithParametersHeaderValue>? _expect;
private bool _expectContinueSet;
private string? _protocol;

#region Request Headers

Expand Down Expand Up @@ -164,11 +164,12 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
/// <value>The value of the <see langword=":protocol" /> pseudo-header for an HTTP request.</value>
public string? Protocol
{
get => _protocol;
get => _specialCollectionsSlots is null ? null : (string?)_specialCollectionsSlots[ProtocolSlot];
set
{
CheckContainsNewLine(value);
_protocol = value;
_specialCollectionsSlots ??= new object[NumCollectionsSlots];
_specialCollectionsSlots[ProtocolSlot] = value;
}
}

Expand Down Expand Up @@ -197,7 +198,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
GetSpecializedCollection(UserAgentSlot, static thisRef => new HttpHeaderValueCollection<ProductInfoHeaderValue>(KnownHeaders.UserAgent.Descriptor, thisRef));

public HttpHeaderValueCollection<NameValueWithParametersHeaderValue> Expect =>
_expect ??= new HttpHeaderValueCollection<NameValueWithParametersHeaderValue>(KnownHeaders.Expect.Descriptor, this);
GetSpecializedCollection(ExpectSlot, static thisRef => new HttpHeaderValueCollection<NameValueWithParametersHeaderValue>(KnownHeaders.Expect.Descriptor, thisRef));

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers;
using System.Text;
Expand All @@ -17,6 +18,7 @@ public class HttpRequestMessage : IDisposable
private const int MessageNotYetSent = 0;
private const int MessageAlreadySent = 1;
private const int MessageIsRedirect = 2;
private const int MessageDisposed = 4;

// Track whether the message has been sent.
// The message shouldn't be sent again if this field is equal to MessageAlreadySent.
Expand All @@ -28,7 +30,6 @@ public class HttpRequestMessage : IDisposable
private Version _version;
private HttpVersionPolicy _versionPolicy;
private HttpContent? _content;
private bool _disposed;
private HttpRequestOptions? _options;

public Version Version
Expand Down Expand Up @@ -168,6 +169,16 @@ public override string ToString()

internal bool WasRedirected() => (_sendStatus & MessageIsRedirect) != 0;

private bool Disposed
{
get => (_sendStatus & MessageDisposed) != 0;
set
{
Debug.Assert(value);
_sendStatus |= MessageDisposed;
}
}

internal bool IsExtendedConnectRequest => Method == HttpMethod.Connect && _headers?.Protocol != null;

#region IDisposable Members
Expand All @@ -176,9 +187,9 @@ protected virtual void Dispose(bool disposing)
{
// The reason for this type to implement IDisposable is that it contains instances of types that implement
// IDisposable (content).
if (disposing && !_disposed)
if (disposing && !Disposed)
{
_disposed = true;
Disposed = true;
_content?.Dispose();
}
}
Expand All @@ -193,7 +204,7 @@ public void Dispose()

private void CheckDisposed()
{
ObjectDisposedException.ThrowIf(_disposed, this);
ObjectDisposedException.ThrowIf(Disposed, this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1528,11 +1528,11 @@ private void WriteHeaders(HttpRequestMessage request, ref ArrayBuffer headerBuff

if (request.HasHeaders)
{
if (request.Headers.Protocol != null)
if (request.Headers.Protocol is string protocol)
{
WriteBytes(ProtocolLiteralHeaderBytes, ref headerBuffer);
Encoding? protocolEncoding = _pool.Settings._requestHeaderEncodingSelector?.Invoke(":protocol", request);
WriteLiteralHeaderValue(request.Headers.Protocol, protocolEncoding, ref headerBuffer);
WriteLiteralHeaderValue(protocol, protocolEncoding, ref headerBuffer);
headerListSize += HeaderField.RfcOverhead;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1043,8 +1043,8 @@ public async ValueTask<HttpResponseMessage> SendWithVersionDetectionAndRetryAsyn
// Use HTTP/3 if possible.
if (IsHttp3Supported() && // guard to enable trimming HTTP/3 support
_http3Enabled &&
!request.IsExtendedConnectRequest &&
(request.Version.Major >= 3 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)))
(request.Version.Major >= 3 || (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher && IsSecure)) &&
!request.IsExtendedConnectRequest)
{
Debug.Assert(async);
response = await TrySendUsingHttp3Async(request, cancellationToken).ConfigureAwait(false);
Expand Down

0 comments on commit 5971947

Please sign in to comment.