| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Diagnostics.CodeAnalysis; |
| | | 5 | | using System.Net.Http.QPack; |
| | | 6 | | |
| | | 7 | | namespace System.Net.Http |
| | | 8 | | { |
| | | 9 | | public partial class HttpMethod : IEquatable<HttpMethod> |
| | | 10 | | { |
| | | 11 | | private readonly string _method; |
| | | 12 | | private int _hashcode; |
| | | 13 | | |
| | 2 | 14 | | public static HttpMethod Get { get; } = new("GET", H3StaticTable.MethodGet); |
| | 1 | 15 | | public static HttpMethod Put { get; } = new("PUT", H3StaticTable.MethodPut); |
| | 1 | 16 | | public static HttpMethod Post { get; } = new("POST", H3StaticTable.MethodPost); |
| | 1 | 17 | | public static HttpMethod Delete { get; } = new("DELETE", H3StaticTable.MethodDelete); |
| | 1 | 18 | | public static HttpMethod Head { get; } = new("HEAD", H3StaticTable.MethodHead); |
| | 1 | 19 | | public static HttpMethod Options { get; } = new("OPTIONS", H3StaticTable.MethodOptions); |
| | 1 | 20 | | public static HttpMethod Trace { get; } = new("TRACE", http3StaticTableIndex: -1); |
| | 1 | 21 | | public static HttpMethod Patch { get; } = new("PATCH", http3StaticTableIndex: -1); |
| | | 22 | | |
| | | 23 | | /// <summary>Gets the HTTP QUERY protocol method.</summary> |
| | | 24 | | /// <value>The HTTP QUERY method.</value> |
| | 1 | 25 | | public static HttpMethod Query { get; } = new("QUERY", http3StaticTableIndex: -1); |
| | | 26 | | |
| | | 27 | | /// <summary>Gets the HTTP CONNECT protocol method.</summary> |
| | | 28 | | /// <value>The HTTP CONNECT method.</value> |
| | 1 | 29 | | public static HttpMethod Connect { get; } = new("CONNECT", H3StaticTable.MethodConnect); |
| | | 30 | | |
| | 0 | 31 | | public string Method => _method; |
| | | 32 | | |
| | 0 | 33 | | public HttpMethod(string method) |
| | 0 | 34 | | { |
| | 0 | 35 | | ArgumentException.ThrowIfNullOrWhiteSpace(method); |
| | 0 | 36 | | if (!HttpRuleParser.IsToken(method)) |
| | 0 | 37 | | { |
| | 0 | 38 | | throw new FormatException(SR.net_http_httpmethod_format_error); |
| | | 39 | | } |
| | | 40 | | |
| | 0 | 41 | | _method = method; |
| | 0 | 42 | | Initialize(method); |
| | 0 | 43 | | } |
| | | 44 | | |
| | 10 | 45 | | private HttpMethod(string method, int http3StaticTableIndex) |
| | 10 | 46 | | { |
| | 10 | 47 | | _method = method; |
| | 10 | 48 | | Initialize(http3StaticTableIndex); |
| | 10 | 49 | | } |
| | | 50 | | |
| | | 51 | | // SocketsHttpHandler-specific implementation has extra init logic. |
| | | 52 | | partial void Initialize(int http3Index); |
| | | 53 | | partial void Initialize(string method); |
| | | 54 | | |
| | | 55 | | public bool Equals([NotNullWhen(true)] HttpMethod? other) => |
| | 0 | 56 | | other is not null && |
| | 0 | 57 | | string.Equals(_method, other._method, StringComparison.OrdinalIgnoreCase); |
| | | 58 | | |
| | | 59 | | public override bool Equals([NotNullWhen(true)] object? obj) => |
| | 0 | 60 | | obj is HttpMethod method && |
| | 0 | 61 | | Equals(method); |
| | | 62 | | |
| | | 63 | | public override int GetHashCode() |
| | 0 | 64 | | { |
| | 0 | 65 | | if (_hashcode == 0) |
| | 0 | 66 | | { |
| | 0 | 67 | | _hashcode = StringComparer.OrdinalIgnoreCase.GetHashCode(_method); |
| | 0 | 68 | | } |
| | | 69 | | |
| | 0 | 70 | | return _hashcode; |
| | 0 | 71 | | } |
| | | 72 | | |
| | 0 | 73 | | public override string ToString() => _method; |
| | | 74 | | |
| | | 75 | | public static bool operator ==(HttpMethod? left, HttpMethod? right) => |
| | 0 | 76 | | left is null || right is null |
| | 0 | 77 | | ? ReferenceEquals(left, right) |
| | 0 | 78 | | : left.Equals(right); |
| | | 79 | | |
| | | 80 | | public static bool operator !=(HttpMethod? left, HttpMethod? right) => |
| | 0 | 81 | | !(left == right); |
| | | 82 | | |
| | | 83 | | /// <summary>Parses the provided <paramref name="method"/> into an <see cref="HttpMethod"/> instance.</summary> |
| | | 84 | | /// <param name="method">The method to parse.</param> |
| | | 85 | | /// <returns>An <see cref="HttpMethod"/> instance for the provided <paramref name="method"/>.</returns> |
| | | 86 | | /// <remarks> |
| | | 87 | | /// This method may return a singleton instance for known methods; for example, it may return <see cref="Get"/> |
| | | 88 | | /// if "GET" is specified. The parsing is performed in a case-insensitive manner, so it may also return <see cre |
| | | 89 | | /// if "get" is specified. For unknown methods, a new <see cref="HttpMethod"/> instance is returned, with the |
| | | 90 | | /// same validation being performed as by the <see cref="HttpMethod(string)"/> constructor. |
| | | 91 | | /// </remarks> |
| | | 92 | | public static HttpMethod Parse(ReadOnlySpan<char> method) => |
| | 0 | 93 | | GetKnownMethod(method) ?? |
| | 0 | 94 | | new HttpMethod(method.ToString()); |
| | | 95 | | |
| | | 96 | | internal static HttpMethod? GetKnownMethod(ReadOnlySpan<char> method) |
| | 0 | 97 | | { |
| | 0 | 98 | | if (method.Length >= 3) // 3 == smallest known method |
| | 0 | 99 | | { |
| | 0 | 100 | | HttpMethod? match = (method[0] | 0x20) switch |
| | 0 | 101 | | { |
| | 0 | 102 | | 'c' => Connect, |
| | 0 | 103 | | 'd' => Delete, |
| | 0 | 104 | | 'g' => Get, |
| | 0 | 105 | | 'h' => Head, |
| | 0 | 106 | | 'o' => Options, |
| | 0 | 107 | | 'p' => method.Length switch |
| | 0 | 108 | | { |
| | 0 | 109 | | 3 => Put, |
| | 0 | 110 | | 4 => Post, |
| | 0 | 111 | | _ => Patch, |
| | 0 | 112 | | }, |
| | 0 | 113 | | 'q' => Query, |
| | 0 | 114 | | 't' => Trace, |
| | 0 | 115 | | _ => null, |
| | 0 | 116 | | }; |
| | | 117 | | |
| | 0 | 118 | | if (match is not null && |
| | 0 | 119 | | method.Equals(match._method, StringComparison.OrdinalIgnoreCase)) |
| | 0 | 120 | | { |
| | 0 | 121 | | return match; |
| | | 122 | | } |
| | 0 | 123 | | } |
| | | 124 | | |
| | 0 | 125 | | return null; |
| | 0 | 126 | | } |
| | | 127 | | } |
| | | 128 | | } |