Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce the size of HttpRequestMessage and HttpRequestHeaders #81251

Merged
merged 2 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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];
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -17,6 +17,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 +29,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 +168,12 @@ public override string ToString()

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

private bool Disposed
{
get => (_sendStatus & MessageDisposed) != 0;
set => _sendStatus |= MessageDisposed;
MihaZupan marked this conversation as resolved.
Show resolved Hide resolved
}

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

#region IDisposable Members
Expand All @@ -176,9 +182,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 +199,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