| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // <copyright>
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- namespace System.ServiceModel.Channels
- {
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Net;
- using System.Net.Http.Headers;
- using System.Runtime;
- using System.Text;
- internal class HttpHeaderInfo
- {
- private static readonly HttpHeaderInfo[] knownContentHeaders = new HttpHeaderInfo[]
- {
- new HttpHeaderInfo("Allow") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Encoding") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Language") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Length") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Location") { IsContentHeader = true },
- new HttpHeaderInfo("Content-MD5") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Range") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Type") { IsContentHeader = true },
- new HttpHeaderInfo("Expires") { IsContentHeader = true },
- new HttpHeaderInfo("Last-Modified") { IsContentHeader = true },
- new HttpHeaderInfo("Content-Disposition") { IsContentHeader = true }
- };
- private static readonly Type httpRequestHeaderType = typeof(HttpRequestHeader);
- private static readonly Type httpResponseHeaderType = typeof(HttpResponseHeader);
- private static ConcurrentDictionary<string, HttpHeaderInfo> knownHeadersInfos;
- private bool isUnknownHeader;
- static HttpHeaderInfo()
- {
- // Create the known headers list with the content headers
- knownHeadersInfos = new ConcurrentDictionary<string, HttpHeaderInfo>(
- knownContentHeaders.ToDictionary(headerInfo => headerInfo.Name),
- StringComparer.OrdinalIgnoreCase);
- // Add the request and response headers to the known headers list
- AddKnownHeaders(Enum.GetNames(httpRequestHeaderType).Select(enumString => GetHeaderString(enumString)), true);
- AddKnownHeaders(Enum.GetNames(httpResponseHeaderType).Select(enumString => GetHeaderString(enumString)), false);
- }
- private HttpHeaderInfo(string name, bool isUnknownHeader = false)
- {
- Fx.Assert(!string.IsNullOrWhiteSpace(name), "The 'name' parameter should not be null or whitespace.");
- this.Name = name;
- this.isUnknownHeader = isUnknownHeader;
- if (this.isUnknownHeader)
- {
- this.IsRequestHeader = true;
- this.IsResponseHeader = true;
- this.IsContentHeader = true;
- }
- }
- public string Name { get; private set; }
- public bool IsRequestHeader { get; private set; }
- public bool IsResponseHeader { get; private set; }
- public bool IsContentHeader { get; private set; }
- public static HttpHeaderInfo Create(string headerName)
- {
- Fx.Assert(!string.IsNullOrWhiteSpace(headerName), "The 'headerName' should not be null or whitespace.");
- HttpHeaderInfo headerInfo;
- if (!knownHeadersInfos.TryGetValue(headerName, out headerInfo))
- {
- headerInfo = new HttpHeaderInfo(headerName, true);
- }
- return headerInfo;
- }
- public bool TryAddHeader(HttpHeaders headers, string value)
- {
- Fx.Assert(headers != null, "The 'headers' parameter should never be null.");
- if (!headers.TryAddWithoutValidation(this.Name, value))
- {
- this.UpdateHeaderInfo(headers);
- return false;
- }
- return true;
- }
- public bool TryRemoveHeader(HttpHeaders headers)
- {
- Fx.Assert(headers != null, "The 'headers' parameter should never be null.");
-
- try
- {
- headers.Remove(this.Name);
- return true;
- }
- catch (InvalidOperationException ex)
- {
- FxTrace.Exception.TraceHandledException(ex, TraceEventType.Information);
- this.UpdateHeaderInfo(headers);
- }
- return false;
- }
- public IEnumerable<string> TryGetHeader(HttpHeaders headers)
- {
- Fx.Assert(headers != null, "The 'headers' parameter should never be null.");
-
- IEnumerable<string> values = null;
- if (!headers.TryGetValues(this.Name, out values))
- {
- values = null;
- this.UpdateHeaderInfo(headers);
- }
- return values;
- }
- private static void AddKnownHeaders(IEnumerable<string> headers, bool asRequestHeader)
- {
- foreach (string header in headers)
- {
- HttpHeaderInfo headerInfo = null;
- if (knownHeadersInfos.TryGetValue(header, out headerInfo))
- {
- if (headerInfo.IsContentHeader)
- {
- // this header is actually a content header so continue
- continue;
- }
- }
- if (headerInfo == null)
- {
- headerInfo = new HttpHeaderInfo(header);
- knownHeadersInfos.TryAdd(headerInfo.Name, headerInfo);
- }
- if (asRequestHeader)
- {
- headerInfo.IsRequestHeader = true;
- }
- else
- {
- headerInfo.IsResponseHeader = true;
- }
- }
- }
- private static string GetHeaderString(string headerEnumString)
- {
- // Have to special case 'ETag' as it should not be hypenated
- if (string.Equals(headerEnumString, HttpResponseHeader.ETag.ToString(), StringComparison.Ordinal))
- {
- return headerEnumString;
- }
- StringBuilder asStringBuilder = new StringBuilder(headerEnumString);
- // Note that we are not considering the first and last characters of the string
- // as headers never start or end with '-'
- for (int i = asStringBuilder.Length - 2; i > 0; i--)
- {
- if (char.IsUpper(asStringBuilder[i]) && char.IsLower(asStringBuilder[i + 1]))
- {
- asStringBuilder.Insert(i, '-');
- }
- }
- return asStringBuilder.ToString();
- }
- private void UpdateHeaderInfo(HttpHeaders headers)
- {
- Fx.Assert(headers != null, "The 'headers' parameter should never be null.");
- if (headers is HttpContentHeaders)
- {
- this.IsContentHeader = false;
- }
- else if (headers is HttpRequestHeaders)
- {
- this.IsRequestHeader = false;
- }
- else if (headers is HttpResponseHeaders)
- {
- this.IsResponseHeader = false;
- }
- if (this.isUnknownHeader)
- {
- this.isUnknownHeader = !knownHeadersInfos.TryAdd(this.Name, this);
- }
- }
- }
- }
|