| | | 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; |
| | | 5 | | |
| | | 6 | | namespace System.Net.Http.Headers |
| | | 7 | | { |
| | | 8 | | // The purpose of this type is to extract the handling of general headers in one place rather than duplicating |
| | | 9 | | // functionality in both HttpRequestHeaders and HttpResponseHeaders. |
| | | 10 | | internal sealed class HttpGeneralHeaders |
| | | 11 | | { |
| | | 12 | | private HttpHeaderValueCollection<string>? _connection; |
| | | 13 | | private HttpHeaderValueCollection<string>? _trailer; |
| | | 14 | | private HttpHeaderValueCollection<TransferCodingHeaderValue>? _transferEncoding; |
| | | 15 | | private HttpHeaderValueCollection<ProductHeaderValue>? _upgrade; |
| | | 16 | | private HttpHeaderValueCollection<ViaHeaderValue>? _via; |
| | | 17 | | private HttpHeaderValueCollection<WarningHeaderValue>? _warning; |
| | | 18 | | private HttpHeaderValueCollection<NameValueHeaderValue>? _pragma; |
| | | 19 | | private readonly HttpHeaders _parent; |
| | | 20 | | private bool _transferEncodingChunkedSet; |
| | | 21 | | private bool _connectionCloseSet; |
| | | 22 | | |
| | | 23 | | public CacheControlHeaderValue? CacheControl |
| | | 24 | | { |
| | 0 | 25 | | get { return (CacheControlHeaderValue?)_parent.GetSingleParsedValue(KnownHeaders.CacheControl.Descriptor); } |
| | 0 | 26 | | set { _parent.SetOrRemoveParsedValue(KnownHeaders.CacheControl.Descriptor, value); } |
| | | 27 | | } |
| | | 28 | | |
| | | 29 | | public bool? ConnectionClose |
| | | 30 | | { |
| | | 31 | | get |
| | 0 | 32 | | { |
| | | 33 | | // Separated out into a static to enable access to TransferEncodingChunked |
| | | 34 | | // without the caller needing to force the creation of HttpGeneralHeaders |
| | | 35 | | // if it wasn't created for other reasons. |
| | 0 | 36 | | return GetConnectionClose(_parent, this); |
| | 0 | 37 | | } |
| | | 38 | | set |
| | 0 | 39 | | { |
| | 0 | 40 | | if (value == true) |
| | 0 | 41 | | { |
| | 0 | 42 | | _connectionCloseSet = true; |
| | 0 | 43 | | if (!_parent.ContainsParsedValue(KnownHeaders.Connection.Descriptor, HeaderUtilities.ConnectionClose |
| | 0 | 44 | | { |
| | 0 | 45 | | _parent.AddParsedValue(KnownHeaders.Connection.Descriptor, HeaderUtilities.ConnectionClose); |
| | 0 | 46 | | } |
| | 0 | 47 | | } |
| | | 48 | | else |
| | 0 | 49 | | { |
| | 0 | 50 | | _connectionCloseSet = value != null; |
| | | 51 | | // We intentionally ignore the return value. It's OK if "close" wasn't in the store. |
| | 0 | 52 | | _parent.RemoveParsedValue(KnownHeaders.Connection.Descriptor, HeaderUtilities.ConnectionClose); |
| | 0 | 53 | | } |
| | 0 | 54 | | } |
| | | 55 | | } |
| | | 56 | | |
| | | 57 | | internal static bool? GetConnectionClose(HttpHeaders parent, HttpGeneralHeaders? headers) |
| | 0 | 58 | | { |
| | 0 | 59 | | if (parent.ContainsParsedValue(KnownHeaders.Connection.Descriptor, HeaderUtilities.ConnectionClose)) |
| | 0 | 60 | | { |
| | 0 | 61 | | return true; |
| | | 62 | | } |
| | 0 | 63 | | if (headers != null && headers._connectionCloseSet) |
| | 0 | 64 | | { |
| | 0 | 65 | | return false; |
| | | 66 | | } |
| | 0 | 67 | | return null; |
| | 0 | 68 | | } |
| | | 69 | | |
| | | 70 | | public DateTimeOffset? Date |
| | | 71 | | { |
| | 0 | 72 | | get { return HeaderUtilities.GetDateTimeOffsetValue(KnownHeaders.Date.Descriptor, _parent); } |
| | 0 | 73 | | set { _parent.SetOrRemoveParsedValue(KnownHeaders.Date.Descriptor, value); } |
| | | 74 | | } |
| | | 75 | | |
| | | 76 | | public HttpHeaderValueCollection<NameValueHeaderValue> Pragma => |
| | 0 | 77 | | _pragma ??= new HttpHeaderValueCollection<NameValueHeaderValue>(KnownHeaders.Pragma.Descriptor, _parent); |
| | | 78 | | |
| | | 79 | | public HttpHeaderValueCollection<string> Trailer => |
| | 0 | 80 | | _trailer ??= new HttpHeaderValueCollection<string>(KnownHeaders.Trailer.Descriptor, _parent); |
| | | 81 | | |
| | | 82 | | internal static bool? GetTransferEncodingChunked(HttpHeaders parent, HttpGeneralHeaders? headers) |
| | 0 | 83 | | { |
| | 0 | 84 | | if (parent.TryGetHeaderValue(KnownHeaders.TransferEncoding.Descriptor, out object? value)) |
| | 0 | 85 | | { |
| | | 86 | | // Fast-path for the very common case where "chunked" is the only value. |
| | 0 | 87 | | if (value is string stringValue && stringValue.Equals("chunked", StringComparison.OrdinalIgnoreCase)) |
| | 0 | 88 | | { |
| | 0 | 89 | | return true; |
| | | 90 | | } |
| | | 91 | | |
| | 0 | 92 | | if (parent.ContainsParsedValue(KnownHeaders.TransferEncoding.Descriptor, HeaderUtilities.TransferEncodin |
| | 0 | 93 | | { |
| | 0 | 94 | | return true; |
| | | 95 | | } |
| | 0 | 96 | | } |
| | | 97 | | |
| | 0 | 98 | | if (headers != null && headers._transferEncodingChunkedSet) |
| | 0 | 99 | | { |
| | 0 | 100 | | return false; |
| | | 101 | | } |
| | | 102 | | |
| | 0 | 103 | | return null; |
| | 0 | 104 | | } |
| | | 105 | | |
| | | 106 | | public bool? TransferEncodingChunked |
| | | 107 | | { |
| | | 108 | | get |
| | 0 | 109 | | { |
| | | 110 | | // Separated out into a static to enable access to TransferEncodingChunked |
| | | 111 | | // without the caller needing to force the creation of HttpGeneralHeaders |
| | | 112 | | // if it wasn't created for other reasons. |
| | 0 | 113 | | return GetTransferEncodingChunked(_parent, this); |
| | 0 | 114 | | } |
| | | 115 | | set |
| | 0 | 116 | | { |
| | 0 | 117 | | if (value == true) |
| | 0 | 118 | | { |
| | 0 | 119 | | _transferEncodingChunkedSet = true; |
| | 0 | 120 | | if (!_parent.ContainsParsedValue(KnownHeaders.TransferEncoding.Descriptor, HeaderUtilities.TransferE |
| | 0 | 121 | | { |
| | 0 | 122 | | _parent.AddParsedValue(KnownHeaders.TransferEncoding.Descriptor, HeaderUtilities.TransferEncodin |
| | 0 | 123 | | } |
| | 0 | 124 | | } |
| | | 125 | | else |
| | 0 | 126 | | { |
| | 0 | 127 | | _transferEncodingChunkedSet = value != null; |
| | | 128 | | // Remove all occurrences of "chunked" in a single pass. |
| | 0 | 129 | | _parent.RemoveParsedValue(KnownHeaders.TransferEncoding.Descriptor, HeaderUtilities.TransferEncoding |
| | 0 | 130 | | } |
| | 0 | 131 | | } |
| | | 132 | | } |
| | | 133 | | |
| | | 134 | | public HttpHeaderValueCollection<ProductHeaderValue> Upgrade => |
| | 0 | 135 | | _upgrade ??= new HttpHeaderValueCollection<ProductHeaderValue>(KnownHeaders.Upgrade.Descriptor, _parent); |
| | | 136 | | |
| | | 137 | | public HttpHeaderValueCollection<ViaHeaderValue> Via => |
| | 0 | 138 | | _via ??= new HttpHeaderValueCollection<ViaHeaderValue>(KnownHeaders.Via.Descriptor, _parent); |
| | | 139 | | |
| | | 140 | | public HttpHeaderValueCollection<WarningHeaderValue> Warning => |
| | 0 | 141 | | _warning ??= new HttpHeaderValueCollection<WarningHeaderValue>(KnownHeaders.Warning.Descriptor, _parent); |
| | | 142 | | |
| | | 143 | | public HttpHeaderValueCollection<string> Connection => |
| | 0 | 144 | | _connection ??= new HttpHeaderValueCollection<string>(KnownHeaders.Connection.Descriptor, _parent); |
| | | 145 | | |
| | | 146 | | public HttpHeaderValueCollection<TransferCodingHeaderValue> TransferEncoding => |
| | 0 | 147 | | _transferEncoding ??= new HttpHeaderValueCollection<TransferCodingHeaderValue>(KnownHeaders.TransferEncoding |
| | | 148 | | |
| | 0 | 149 | | internal HttpGeneralHeaders(HttpHeaders parent) |
| | 0 | 150 | | { |
| | 0 | 151 | | Debug.Assert(parent != null); |
| | | 152 | | |
| | 0 | 153 | | _parent = parent; |
| | 0 | 154 | | } |
| | | 155 | | |
| | | 156 | | internal void AddSpecialsFrom(HttpGeneralHeaders sourceHeaders) |
| | 0 | 157 | | { |
| | | 158 | | // Copy special values, but do not overwrite |
| | 0 | 159 | | bool? chunked = TransferEncodingChunked; |
| | 0 | 160 | | if (!chunked.HasValue) |
| | 0 | 161 | | { |
| | 0 | 162 | | TransferEncodingChunked = sourceHeaders.TransferEncodingChunked; |
| | 0 | 163 | | } |
| | | 164 | | |
| | 0 | 165 | | bool? close = ConnectionClose; |
| | 0 | 166 | | if (!close.HasValue) |
| | 0 | 167 | | { |
| | 0 | 168 | | ConnectionClose = sourceHeaders.ConnectionClose; |
| | 0 | 169 | | } |
| | 0 | 170 | | } |
| | | 171 | | } |
| | | 172 | | } |