| File: System\Net\Security\SslApplicationProtocol.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Security\src\System.Net.Security.csproj (System.Net.Security) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; namespace System.Net.Security { public readonly struct SslApplicationProtocol : IEquatable<SslApplicationProtocol> { private static readonly Encoding s_utf8 = Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); private static readonly byte[] s_http3Utf8 = "h3"u8.ToArray(); private static readonly byte[] s_http2Utf8 = "h2"u8.ToArray(); private static readonly byte[] s_http11Utf8 = "http/1.1"u8.ToArray(); // Refer to IANA on ApplicationProtocols: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 3.0.</summary> public static readonly SslApplicationProtocol Http3 = new SslApplicationProtocol(s_http3Utf8, copy: false); /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 2.0.</summary> public static readonly SslApplicationProtocol Http2 = new SslApplicationProtocol(s_http2Utf8, copy: false); /// <summary>Defines a <see cref="SslApplicationProtocol"/> instance for HTTP 1.1.</summary> public static readonly SslApplicationProtocol Http11 = new SslApplicationProtocol(s_http11Utf8, copy: false); private readonly byte[] _readOnlyProtocol; internal SslApplicationProtocol(byte[] protocol, bool copy) { Debug.Assert(protocol != null); // RFC 7301 states protocol size <= 255 bytes. if (protocol.Length == 0 || protocol.Length > 255) { throw new ArgumentException(SR.net_ssl_app_protocol_invalid, nameof(protocol)); } _readOnlyProtocol = copy ? protocol.AsSpan().ToArray() : protocol; } public SslApplicationProtocol(byte[] protocol) : this(protocol ?? throw new ArgumentNullException(nameof(protocol)), copy: true) { } public SslApplicationProtocol(string protocol) : this(s_utf8.GetBytes(protocol ?? throw new ArgumentNullException(nameof(protocol))), copy: false) { } public ReadOnlyMemory<byte> Protocol => _readOnlyProtocol; public bool Equals(SslApplicationProtocol other) => ((ReadOnlySpan<byte>)_readOnlyProtocol).SequenceEqual(other._readOnlyProtocol); public override bool Equals([NotNullWhen(true)] object? obj) => obj is SslApplicationProtocol protocol && Equals(protocol); public override int GetHashCode() { byte[] arr = _readOnlyProtocol; if (arr == null) { return 0; } int hash = 0; for (int i = 0; i < arr.Length; i++) { hash = ((hash << 5) + hash) ^ arr[i]; } return hash; } public override string ToString() { byte[] arr = _readOnlyProtocol; try { return arr is null ? string.Empty : ReferenceEquals(arr, s_http3Utf8) ? "h3" : ReferenceEquals(arr, s_http2Utf8) ? "h2" : ReferenceEquals(arr, s_http11Utf8) ? "http/1.1" : s_utf8.GetString(arr); } catch { // In case of decoding errors, return the byte values as hex string. char[] byteChars = new char[arr.Length * 5]; int index = 0; for (int i = 0; i < byteChars.Length; i += 5) { byte b = arr[index++]; byteChars[i] = '0'; byteChars[i + 1] = 'x'; byteChars[i + 2] = HexConverter.ToCharLower(b >> 4); byteChars[i + 3] = HexConverter.ToCharLower(b); byteChars[i + 4] = ' '; } return new string(byteChars, 0, byteChars.Length - 1); } } public static bool operator ==(SslApplicationProtocol left, SslApplicationProtocol right) => left.Equals(right); public static bool operator !=(SslApplicationProtocol left, SslApplicationProtocol right) => !(left == right); } }