diff options
Diffstat (limited to 'Net.Http/src')
48 files changed, 0 insertions, 11366 deletions
diff --git a/Net.Http/src/AlternateProtocolBase.cs b/Net.Http/src/AlternateProtocolBase.cs deleted file mode 100644 index 929bc33..0000000 --- a/Net.Http/src/AlternateProtocolBase.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: AlternateProtocolBase.cs -* -* AlternateProtocolBase.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Net.Http.Core; - -namespace VNLib.Net.Http -{ - /// <summary> - /// A base class for all non-http protocol handlers - /// </summary> - public abstract class AlternateProtocolBase : MarshalByRefObject, IAlternateProtocol - { - /// <summary> - /// A cancelation source that allows for canceling running tasks, that is linked - /// to the server that called <see cref="RunAsync(Stream)"/>. - /// </summary> - /// <remarks> - /// This property is only available while the <see cref="RunAsync(Stream)"/> - /// method is executing - /// </remarks> -#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - protected CancellationTokenSource CancelSource { get; private set; } -#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - - ///<inheritdoc/> - async Task IAlternateProtocol.RunAsync(Stream transport, CancellationToken handlerToken) - { - //Create new cancel source - CancelSource ??= new(); - //Register the token to cancel the source and save the registration for unregister on dispose - CancellationTokenRegistration Registration = handlerToken.Register(CancelSource.Cancel); - try - { - //Call child initialize method - await RunAsync(new AlternateProtocolTransportStreamWrapper(transport)); - CancelSource.Cancel(); - } - finally - { - //dispose the cancelation registration - await Registration.DisposeAsync(); - //Dispose cancel source - CancelSource.Dispose(); - } - } - - /// <summary> - /// Is the current socket connected using transport security - /// </summary> - public virtual bool IsSecure { get; init; } - - /// <summary> - /// Determines if the instance is pending cancelation - /// </summary> - public bool IsCancellationRequested => CancelSource.IsCancellationRequested; - - /// <summary> - /// Cancels all pending operations. This session will be unusable after this function is called - /// </summary> - public virtual void CancelAll() => CancelSource?.Cancel(); - - /// <summary> - /// Called when the protocol swtich handshake has completed and the transport is - /// available for the new protocol - /// </summary> - /// <param name="transport">The transport stream</param> - /// <returns>A task that represents the active use of the transport, and when complete all operations are unwound</returns> - protected abstract Task RunAsync(Stream transport); - } -}
\ No newline at end of file diff --git a/Net.Http/src/ConnectionInfo.cs b/Net.Http/src/ConnectionInfo.cs deleted file mode 100644 index 6e1660d..0000000 --- a/Net.Http/src/ConnectionInfo.cs +++ /dev/null @@ -1,166 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ConnectionInfo.cs -* -* ConnectionInfo.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Linq; -using System.Text; -using System.Collections.Generic; -using System.Security.Authentication; - -using VNLib.Net.Http.Core; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http -{ - ///<inheritdoc/> - internal sealed class ConnectionInfo : IConnectionInfo - { - private HttpContext Context; - - ///<inheritdoc/> - public Uri RequestUri => Context.Request.Location; - ///<inheritdoc/> - public string Path => RequestUri.LocalPath; - ///<inheritdoc/> - public string? UserAgent => Context.Request.UserAgent; - ///<inheritdoc/> - public IHeaderCollection Headers { get; private set; } - ///<inheritdoc/> - public bool CrossOrigin { get; } - ///<inheritdoc/> - public bool IsWebSocketRequest { get; } - ///<inheritdoc/> - public ContentType ContentType => Context.Request.ContentType; - ///<inheritdoc/> - public HttpMethod Method => Context.Request.Method; - ///<inheritdoc/> - public HttpVersion ProtocolVersion => Context.Request.HttpVersion; - ///<inheritdoc/> - public bool IsSecure => Context.Request.EncryptionVersion != SslProtocols.None; - ///<inheritdoc/> - public SslProtocols SecurityProtocol => Context.Request.EncryptionVersion; - ///<inheritdoc/> - public Uri? Origin => Context.Request.Origin; - ///<inheritdoc/> - public Uri? Referer => Context.Request.Referrer; - ///<inheritdoc/> - public Tuple<long, long>? Range => Context.Request.Range; - ///<inheritdoc/> - public IPEndPoint LocalEndpoint => Context.Request.LocalEndPoint; - ///<inheritdoc/> - public IPEndPoint RemoteEndpoint => Context.Request.RemoteEndPoint; - ///<inheritdoc/> - public Encoding Encoding => Context.ParentServer.Config.HttpEncoding; - ///<inheritdoc/> - public IReadOnlyDictionary<string, string> RequestCookies => Context.Request.Cookies; - ///<inheritdoc/> - public IEnumerable<string> Accept => Context.Request.Accept; - ///<inheritdoc/> - public TransportSecurityInfo? TransportSecurity => Context.GetSecurityInfo(); - - ///<inheritdoc/> - public bool Accepts(ContentType type) - { - //Get the content type string from he specified content type - string contentType = HttpHelpers.GetContentTypeString(type); - return Accepts(contentType); - } - ///<inheritdoc/> - public bool Accepts(string contentType) - { - if (AcceptsAny()) - { - return true; - } - - //If client accepts exact requested encoding - if (Accept.Contains(contentType)) - { - return true; - } - - //Search accept types to determine if the content type is acceptable - bool accepted = Accept - .Where(ctype => - { - //Get prinary side of mime type - ReadOnlySpan<char> primary = contentType.AsSpan().SliceBeforeParam('/'); - ReadOnlySpan<char> ctSubType = ctype.AsSpan().SliceBeforeParam('/'); - //See if accepts any subtype, or the primary sub-type matches - return ctSubType[0] == '*' || ctSubType.Equals(primary, StringComparison.OrdinalIgnoreCase); - }).Any(); - return accepted; - } - /// <summary> - /// Determines if the connection accepts any content type - /// </summary> - /// <returns>true if the connection accepts any content typ, false otherwise</returns> - private bool AcceptsAny() - { - //Accept any if no accept header was present, or accept all value */* - return Context.Request.Accept.Count == 0 || Accept.Where(static t => t.StartsWith("*/*", StringComparison.OrdinalIgnoreCase)).Any(); - } - ///<inheritdoc/> - public void SetCookie(string name, string value, string? domain, string? path, TimeSpan Expires, CookieSameSite sameSite, bool httpOnly, bool secure) - { - //Create the new cookie - HttpCookie cookie = new(name) - { - Value = value, - Domain = domain, - Path = path, - MaxAge = Expires, - //Set the session lifetime flag if the timeout is max value - IsSession = Expires == TimeSpan.MaxValue, - //If the connection is cross origin, then we need to modify the secure and samsite values - SameSite = CrossOrigin ? CookieSameSite.None : sameSite, - Secure = secure | CrossOrigin, - HttpOnly = httpOnly - }; - //Set the cookie - Context.Response.AddCookie(cookie); - } - - internal ConnectionInfo(HttpContext ctx) - { - //Create new header collection - Headers = new VnHeaderCollection(ctx); - //set co value - CrossOrigin = ctx.Request.IsCrossOrigin(); - //Set websocket status - IsWebSocketRequest = ctx.Request.IsWebSocketRequest(); - //Update the context referrence - Context = ctx; - } - -#nullable disable - internal void Clear() - { - Context = null; - (Headers as VnHeaderCollection).Clear(); - Headers = null; - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/HttpContext.cs b/Net.Http/src/Core/HttpContext.cs deleted file mode 100644 index 43d1975..0000000 --- a/Net.Http/src/Core/HttpContext.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpContext.cs -* -* HttpContext.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Runtime.CompilerServices; - -using VNLib.Utils; -using VNLib.Utils.Memory.Caching; - - -namespace VNLib.Net.Http.Core -{ - internal sealed partial class HttpContext : IConnectionContext, IReusable - { - /// <summary> - /// When set as a response flag, disables response compression for - /// the current request/response flow - /// </summary> - public const ulong COMPRESSION_DISABLED_MSK = 0x01UL; - - /// <summary> - /// The reusable http request container - /// </summary> - public readonly HttpRequest Request; - /// <summary> - /// The reusable response controler - /// </summary> - public readonly HttpResponse Response; - /// <summary> - /// The http server that this context is bound to - /// </summary> - public readonly HttpServer ParentServer; - /// <summary> - /// The shared transport header reader buffer - /// </summary> - public readonly SharedHeaderReaderBuffer RequestBuffer; - - /// <summary> - /// The response entity body container - /// </summary> - public readonly IHttpResponseBody ResponseBody; - - /// <summary> - /// A collection of flags that can be used to control the way the context - /// responds to client requests - /// </summary> - public readonly BitField ContextFlags; - - /// <summary> - /// Gets or sets the alternate application protocol to swtich to - /// </summary> - public IAlternateProtocol? AlternateProtocol { get; set; } - - private readonly ResponseWriter responseWriter; - private ITransportContext? _ctx; - - public HttpContext(HttpServer server) - { - /* - * Local method for retreiving the transport stream, - * this adds protection/debug from response/request - * containers not allowed to maintain referrences - * to a transport stream after it has been released - */ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - Stream GetStream() => _ctx!.ConnectionStream; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - HttpVersion GetVersion() => Request.HttpVersion; - - ParentServer = server; - - //Create new request - Request = new HttpRequest(GetStream); - - //create a new response object - Response = new HttpResponse( - server.Config.HttpEncoding, - ParentServer.Config.ResponseHeaderBufferSize, - ParentServer.Config.ChunkedResponseAccumulatorSize, - GetStream, - GetVersion); - - //The shared request parsing buffer - RequestBuffer = new(server.Config.HeaderBufferSize); - - //Init response writer - ResponseBody = responseWriter = new ResponseWriter(); - - ContextFlags = new(0); - } - - public TransportSecurityInfo? GetSecurityInfo() => _ctx?.GetSecurityInfo(); - - - #region LifeCycle Hooks - - ///<inheritdoc/> - public void InitializeContext(ITransportContext ctx) => _ctx = ctx; - - ///<inheritdoc/> - public void BeginRequest() - { - //Clear all flags - ContextFlags.ClearAll(); - - //Lifecycle on new request - Request.OnNewRequest(); - Response.OnNewRequest(); - RequestBuffer.OnNewRequest(); - - //Initialize the request - Request.Initialize(_ctx!, ParentServer.Config.DefaultHttpVersion); - } - - ///<inheritdoc/> - public void EndRequest() - { - AlternateProtocol = null; - - Request.OnComplete(); - Response.OnComplete(); - RequestBuffer.OnComplete(); - responseWriter.OnComplete(); - } - - void IReusable.Prepare() - { - Request.OnPrepare(); - Response.OnPrepare(); - RequestBuffer.OnPrepare(); - } - - bool IReusable.Release() - { - _ctx = null; - - //Release response/requqests - Request.OnRelease(); - Response.OnRelease(); - RequestBuffer.OnRelease(); - - return true; - } - - #endregion - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/HttpCookie.cs b/Net.Http/src/Core/HttpCookie.cs deleted file mode 100644 index f5408b2..0000000 --- a/Net.Http/src/Core/HttpCookie.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpCookie.cs -* -* HttpCookie.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; - -using VNLib.Utils; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - internal class HttpCookie : IStringSerializeable, IEquatable<HttpCookie> - { - public string Name { get; } - public string? Value { get; init; } - public string? Domain { get; init; } - public string? Path { get; init; } - public TimeSpan MaxAge { get; init; } - public CookieSameSite SameSite { get; init; } - public bool Secure { get; init; } - public bool HttpOnly { get; init; } - public bool IsSession { get; init; } - - public HttpCookie(string name) - { - this.Name = name; - } - - public string Compile() - { - throw new NotImplementedException(); - } - public void Compile(ref ForwardOnlyWriter<char> writer) - { - //set the name of the cookie - writer.Append(Name); - writer.Append('='); - //set name - writer.Append(Value); - //Only set the max age parameter if the cookie is not a session cookie - if (!IsSession) - { - writer.Append("; Max-Age="); - writer.Append((int)MaxAge.TotalSeconds); - } - //Make sure domain is set - if (!string.IsNullOrWhiteSpace(Domain)) - { - writer.Append("; Domain="); - writer.Append(Domain); - } - //Check and set path - if (!string.IsNullOrWhiteSpace(Path)) - { - //Set path - writer.Append("; Path="); - writer.Append(Path); - } - writer.Append("; SameSite="); - //Set the samesite flag based on the enum value - switch (SameSite) - { - case CookieSameSite.None: - writer.Append("None"); - break; - case CookieSameSite.SameSite: - writer.Append("Strict"); - break; - case CookieSameSite.Lax: - default: - writer.Append("Lax"); - break; - } - //Set httponly flag - if (HttpOnly) - { - writer.Append("; HttpOnly"); - } - //Set secure flag - if (Secure) - { - writer.Append("; Secure"); - } - } - public ERRNO Compile(in Span<char> buffer) - { - ForwardOnlyWriter<char> writer = new(buffer); - Compile(ref writer); - return writer.Written; - } - - public override int GetHashCode() => Name.GetHashCode(); - - public override bool Equals(object? obj) - { - return obj is HttpCookie other && Equals(other); - } - - public bool Equals(HttpCookie? other) - { - return other != null && Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/HttpEvent.cs b/Net.Http/src/Core/HttpEvent.cs deleted file mode 100644 index 7d7c1e7..0000000 --- a/Net.Http/src/Core/HttpEvent.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpEvent.cs -* -* HttpEvent.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -using VNLib.Net.Http.Core; - -namespace VNLib.Net.Http -{ - internal sealed class HttpEvent : MarshalByRefObject, IHttpEvent - { - private HttpContext Context; - private ConnectionInfo _ci; - - internal HttpEvent(HttpContext ctx) - { - Context = ctx; - _ci = new ConnectionInfo(ctx); - } - - ///<inheritdoc/> - IConnectionInfo IHttpEvent.Server => _ci; - - ///<inheritdoc/> - HttpServer IHttpEvent.OriginServer => Context.ParentServer; - - ///<inheritdoc/> - IReadOnlyDictionary<string, string> IHttpEvent.QueryArgs => Context.Request.RequestBody.QueryArgs; - ///<inheritdoc/> - IReadOnlyDictionary<string, string> IHttpEvent.RequestArgs => Context.Request.RequestBody.RequestArgs; - ///<inheritdoc/> - IReadOnlyList<FileUpload> IHttpEvent.Files => Context.Request.RequestBody.Uploads; - - ///<inheritdoc/> - void IHttpEvent.DisableCompression() => Context.ContextFlags.Set(HttpContext.COMPRESSION_DISABLED_MSK); - - ///<inheritdoc/> - void IHttpEvent.DangerousChangeProtocol(IAlternateProtocol protocolHandler) - { - if(Context.AlternateProtocol != null) - { - throw new InvalidOperationException("A protocol handler was already specified"); - } - - _ = protocolHandler ?? throw new ArgumentNullException(nameof(protocolHandler)); - - //Set 101 status code - Context.Respond(HttpStatusCode.SwitchingProtocols); - Context.AlternateProtocol = protocolHandler; - } - - ///<inheritdoc/> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void IHttpEvent.CloseResponse(HttpStatusCode code) => Context.Respond(code); - - ///<inheritdoc/> - void IHttpEvent.CloseResponse(HttpStatusCode code, ContentType type, Stream stream) - { - //Check if the stream is valid. We will need to read the stream, and we will also need to get the length property - if (!stream.CanSeek || !stream.CanRead) - { - throw new IOException("The stream.Length property must be available and the stream must be readable"); - } - - //If stream is empty, ignore it, the server will default to 0 content length and avoid overhead - if (stream.Length == 0) - { - return; - } - - //Set status code - Context.Response.SetStatusCode(code); - - //Finally store the stream input - if(!(Context.ResponseBody as ResponseWriter)!.TrySetResponseBody(stream)) - { - throw new InvalidOperationException("A response body has already been set"); - } - - //Set content type header after body - Context.Response.Headers[HttpResponseHeader.ContentType] = HttpHelpers.GetContentTypeString(type); - } - - ///<inheritdoc/> - void IHttpEvent.CloseResponse(HttpStatusCode code, ContentType type, IMemoryResponseReader entity) - { - //If stream is empty, ignore it, the server will default to 0 content length and avoid overhead - if (entity.Remaining == 0) - { - return; - } - - //Set status code - Context.Response.SetStatusCode(code); - - //Finally store the stream input - if (!(Context.ResponseBody as ResponseWriter)!.TrySetResponseBody(entity)) - { - throw new InvalidOperationException("A response body has already been set"); - } - - //Set content type header after body - Context.Response.Headers[HttpResponseHeader.ContentType] = HttpHelpers.GetContentTypeString(type); - } - -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. - internal void Clear() - { - //Clean up referrence types and cleanable objects - Context = null; - _ci.Clear(); - _ci = null; - } -#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/HttpServerBase.cs b/Net.Http/src/Core/HttpServerBase.cs deleted file mode 100644 index 3a50672..0000000 --- a/Net.Http/src/Core/HttpServerBase.cs +++ /dev/null @@ -1,312 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpServerBase.cs -* -* HttpServerBase.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -/* - * This file is the base of the HTTP server class that provides - * consts, statics, fields, and properties of the HttpServer class. - * - * Processing of HTTP connections and entities is contained in the - * processing partial file. - * - * Processing is configured to be asynchronous, utilizing .NETs - * asynchronous compilation services. To facilitate this but continue - * to use object caching, reusable stores must be usable across threads - * to function safely with async programming practices. - */ - -using System; -using System.Linq; -using System.Threading; -using System.Net.Sockets; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.Security.Authentication; - -using VNLib.Utils.Logging; -using VNLib.Utils.Memory.Caching; - -using VNLib.Net.Http.Core; - -namespace VNLib.Net.Http -{ - - /// <summary> - /// Provides a resource efficient, high performance, single library HTTP(s) server, - /// with extensable processors and transport providers. - /// This class cannot be inherited - /// </summary> - public sealed partial class HttpServer : ICacheHolder - { - /// <summary> - /// The host key that determines a "wildcard" host, meaning the - /// default connection handler when an incomming connection has - /// not specific route - /// </summary> - public const string WILDCARD_KEY = "*"; - - private readonly ITransportProvider Transport; - private readonly IReadOnlyDictionary<string, IWebRoot> ServerRoots; - - #region caches - /// <summary> - /// The cached HTTP1/1 keepalive timeout header value - /// </summary> - private readonly string KeepAliveTimeoutHeaderValue; - /// <summary> - /// Reusable store for obtaining <see cref="HttpContext"/> - /// </summary> - private readonly ObjectRental<HttpContext> ContextStore; - /// <summary> - /// The cached header-line termination value - /// </summary> - private readonly ReadOnlyMemory<byte> HeaderLineTermination; - #endregion - - /// <summary> - /// The <see cref="HttpConfig"/> for the current server - /// </summary> - public HttpConfig Config { get; } - - /// <summary> - /// Gets a value indicating whether the server is listening for connections - /// </summary> - public bool Running { get; private set; } - - private CancellationTokenSource? StopToken; - - /// <summary> - /// Creates a new <see cref="HttpServer"/> with the specified configration copy (using struct). - /// Immutable data structures are initialzed. - /// </summary> - /// <param name="config">The configuration used to create the instance</param> - /// <param name="transport">The transport provider to listen to connections from</param> - /// <param name="sites">A collection of <see cref="IWebRoot"/>s that route incomming connetctions</param> - /// <exception cref="ArgumentException"></exception> - public HttpServer(HttpConfig config, ITransportProvider transport, IEnumerable<IWebRoot> sites) - { - //Validate the configuration - ValidateConfig(in config); - - Config = config; - //Configure roots and their directories - ServerRoots = sites.ToDictionary(static r => r.Hostname, static tv => tv, StringComparer.OrdinalIgnoreCase); - //Compile and store the timeout keepalive header - KeepAliveTimeoutHeaderValue = $"timeout={(int)Config.ConnectionKeepAlive.TotalSeconds}"; - //Store termination for the current instance - HeaderLineTermination = config.HttpEncoding.GetBytes(HttpHelpers.CRLF); - //Create a new context store - ContextStore = ObjectRental.CreateReusable(() => new HttpContext(this)); - //Setup config copy with the internal http pool - Transport = transport; - } - - private static void ValidateConfig(in HttpConfig conf) - { - _ = conf.HttpEncoding ?? throw new ArgumentException("HttpEncoding cannot be null", nameof(conf)); - _ = conf.ServerLog ?? throw new ArgumentException("ServerLog cannot be null", nameof(conf)); - - if (conf.ActiveConnectionRecvTimeout < -1) - { - throw new ArgumentException("ActiveConnectionRecvTimeout cannot be less than -1", nameof(conf)); - } - - //Chunked data accumulator must be at least 64 bytes (arbinrary value) - if (conf.ChunkedResponseAccumulatorSize < 64 || conf.ChunkedResponseAccumulatorSize == int.MaxValue) - { - throw new ArgumentException("ChunkedResponseAccumulatorSize cannot be less than 64 bytes", nameof(conf)); - } - - if (conf.CompressionLimit < 0) - { - throw new ArgumentException("CompressionLimit cannot be less than 0, set to 0 to disable response compression", nameof(conf)); - } - - if (conf.ConnectionKeepAlive < TimeSpan.Zero) - { - throw new ArgumentException("ConnectionKeepAlive cannot be less than 0", nameof(conf)); - } - - if (conf.DefaultHttpVersion == HttpVersion.NotSupported) - { - throw new ArgumentException("DefaultHttpVersion cannot be NotSupported", nameof(conf)); - } - - if (conf.DiscardBufferSize < 64) - { - throw new ArgumentException("DiscardBufferSize cannot be less than 64 bytes", nameof(conf)); - } - - if (conf.FormDataBufferSize < 64) - { - throw new ArgumentException("FormDataBufferSize cannot be less than 64 bytes", nameof(conf)); - } - - if (conf.HeaderBufferSize < 128) - { - throw new ArgumentException("HeaderBufferSize cannot be less than 128 bytes", nameof(conf)); - } - - if (conf.MaxFormDataUploadSize < 0) - { - throw new ArgumentException("MaxFormDataUploadSize cannot be less than 0, set to 0 to disable form-data uploads", nameof(conf)); - } - - if (conf.MaxOpenConnections < 0) - { - throw new ArgumentException("MaxOpenConnections cannot be less than 0", nameof(conf)); - } - - if (conf.MaxRequestHeaderCount < 1) - { - throw new ArgumentException("MaxRequestHeaderCount cannot be less than 1", nameof(conf)); - } - - if (conf.MaxUploadSize < 0) - { - throw new ArgumentException("MaxUploadSize cannot be less than 0", nameof(conf)); - } - - if (conf.ResponseBufferSize < 64) - { - throw new ArgumentException("ResponseBufferSize cannot be less than 64 bytes", nameof(conf)); - } - - if (conf.ResponseHeaderBufferSize < 128) - { - throw new ArgumentException("ResponseHeaderBufferSize cannot be less than 128 bytes", nameof(conf)); - } - - if (conf.SendTimeout < 1) - { - throw new ArgumentException("SendTimeout cannot be less than 1 millisecond", nameof(conf)); - } - } - - /// <summary> - /// Begins listening for connections on configured interfaces for configured hostnames. - /// </summary> - /// <param name="token">A token used to stop listening for incomming connections and close all open websockets</param> - /// <returns>A task that resolves when the server has exited</returns> - /// <exception cref="SocketException"></exception> - /// <exception cref="ThreadStateException"></exception> - /// <exception cref="ObjectDisposedException"></exception> - /// <exception cref="InvalidOperationException"></exception> - public Task Start(CancellationToken token) - { - StopToken = CancellationTokenSource.CreateLinkedTokenSource(token); - //Start servers with the new token source - Transport.Start(token); - //Start the listen task - return Task.Run(ListenWorkerDoWork, token); - } - - /* - * An SslStream may throw a win32 exception with HRESULT 0x80090327 - * when processing a client certificate (I believe anyway) only - * an issue on some clients (browsers) - */ - - private const int UKNOWN_CERT_AUTH_HRESULT = unchecked((int)0x80090327); - - /// <summary> - /// An invlaid frame size may happen if data is recieved on an open socket - /// but does not contain valid SSL handshake data - /// </summary> - private const int INVALID_FRAME_HRESULT = unchecked((int)0x80131620); - - /* - * A worker task that listens for connections from the transport - */ - private async Task ListenWorkerDoWork() - { - //Set running flag - Running = true; - - Config.ServerLog.Information("HTTP server {hc} listening for connections", GetHashCode()); - //Listen for connections until canceled - while (true) - { - try - { - //Listen for new connection - ITransportContext ctx = await Transport.AcceptAsync(StopToken!.Token); - //Try to dispatch the recieved event - _ = DataReceivedAsync(ctx).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - //Closing, exit loop - break; - } - catch (AuthenticationException ae) - { - Config.ServerLog.Error(ae); - } - catch (Exception ex) - { - Config.ServerLog.Error(ex); - } - } - //Clear all caches - CacheHardClear(); - //Clear running flag - Running = false; - Config.ServerLog.Information("HTTP server {hc} exiting", GetHashCode()); - } - - - ///<inheritdoc/> - ///<exception cref="ObjectDisposedException"></exception> - public void CacheClear() => ContextStore.CacheClear(); - - /// <inheritdoc/> - /// <exception cref="ObjectDisposedException"></exception> - public void CacheHardClear() => ContextStore.CacheHardClear(); - - /// <summary> - /// Writes the specialized log for a socket exception - /// </summary> - /// <param name="se">The socket exception to log</param> - public void WriteSocketExecption(SocketException se) - { - //When clause guards nulls - switch (se.SocketErrorCode) - - { - //Ignore aborted messages - case SocketError.ConnectionAborted: - return; - case SocketError.ConnectionReset: - Config.ServerLog.Debug("Connecion reset by client"); - return; - case SocketError.TimedOut: - Config.ServerLog.Debug("Socket operation timed out"); - return; - default: - Config.ServerLog.Information(se); - break; - } - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/HttpServerProcessing.cs b/Net.Http/src/Core/HttpServerProcessing.cs deleted file mode 100644 index 881b66c..0000000 --- a/Net.Http/src/Core/HttpServerProcessing.cs +++ /dev/null @@ -1,387 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpServerProcessing.cs -* -* HttpServerProcessing.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Threading; -using System.Net.Sockets; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; - -using VNLib.Utils; -using VNLib.Utils.Logging; -using VNLib.Net.Http.Core; - -namespace VNLib.Net.Http -{ - public sealed partial class HttpServer - { - - private int OpenConnectionCount; - - //Event handler method for processing incoming data events - private async Task DataReceivedAsync(ITransportContext transportContext) - { - //Increment open connection count - Interlocked.Increment(ref OpenConnectionCount); - - //Rent a new context object to reuse - HttpContext context = ContextStore.Rent(); - - try - { - //Set write timeout - transportContext.ConnectionStream.WriteTimeout = Config.SendTimeout; - - //Init stream - context.InitializeContext(transportContext); - - //Keep the transport open and listen for messages as long as keepalive is enabled - do - { - //Set rx timeout low for initial reading - transportContext.ConnectionStream.ReadTimeout = Config.ActiveConnectionRecvTimeout; - - //Process the request - ERRNO keepalive = await ProcessHttpEventAsync(transportContext, context); - - //If the connection is closed, we can return - if (!keepalive) - { - break; - } - - //Set inactive keeaplive timeout - transportContext.ConnectionStream.ReadTimeout = (int)Config.ConnectionKeepAlive.TotalMilliseconds; - - //"Peek" or wait for more data to begin another request (may throw timeout exception when timmed out) - await transportContext.ConnectionStream.ReadAsync(Memory<byte>.Empty, StopToken!.Token); - - } while (true); - } - //Catch wrapped socket exceptions - catch(IOException ioe) when(ioe.InnerException is SocketException se) - { - WriteSocketExecption(se); - } - catch(SocketException se) - { - WriteSocketExecption(se); - } - catch (OperationCanceledException oce) - { - Config.ServerLog.Debug("Failed to receive transport data within a timeout period {m}, connection closed", oce.Message); - } - catch(Exception ex) - { - Config.ServerLog.Error(ex); - } - - //Dec open connection count - Interlocked.Decrement(ref OpenConnectionCount); - - //Return context to store - ContextStore.Return(context); - - //Close the transport async - try - { - await transportContext.CloseConnectionAsync(); - } - catch(Exception ex) - { - Config.ServerLog.Error(ex); - } - } - - - /// <summary> - /// Main event handler for all incoming connections - /// </summary> - /// <param name="transportContext">The <see cref="ITransportContext"/> describing the incoming connection</param> - /// <param name="context">Reusable context object</param> - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - private async Task<ERRNO> ProcessHttpEventAsync(ITransportContext transportContext, HttpContext context) - { - //Prepare http context to process a new message - context.BeginRequest(); - - try - { - //Try to parse the http request (may throw exceptions, let them propagate to the transport layer) - int status = (int)ParseRequest(transportContext, context); - - //Check status code for socket error, if so, return false to close the connection - if (status >= 1000) - { - return false; - } -#if DEBUG - //Write debug request log - if (Config.RequestDebugLog != null) - { - Config.RequestDebugLog.Verbose(context.Request.ToString()); - } -#endif - //process the request - ERRNO keepalive = await ProcessRequestAsync(context, (HttpStatusCode)status); - //Store alternate protocol if set - IAlternateProtocol? alternateProtocol = context.AlternateProtocol; - //Close the response - await context.WriteResponseAsync(StopToken!.Token); - //See if an alterate protocol was specified - if (alternateProtocol != null) - { - //Disable transport timeouts - transportContext.ConnectionStream.WriteTimeout = Timeout.Infinite; - transportContext.ConnectionStream.ReadTimeout = Timeout.Infinite; - //Exec the protocol handler and pass the transport stream - await alternateProtocol.RunAsync(transportContext.ConnectionStream, StopToken!.Token); - - //Clear keepalive flag to close the connection - keepalive = false; - } - - return keepalive; - } - finally - { - //Clean end request - context.EndRequest(); - } - } - - /// <summary> - /// Reads data synchronously from the transport and attempts to parse an HTTP message and - /// built a request. - /// </summary> - /// <param name="transport"></param> - /// <param name="ctx"></param> - /// <returns>0 if the request was successfully parsed, the <see cref="HttpStatusCode"/> - /// to return to the client because the entity could not be processed</returns> - /// <remarks> - /// <para> - /// This method is synchronous for multiple memory optimization reasons, - /// and performance is not expected to be reduced as the transport layer should - /// <br></br> - /// only raise an event when a socket has data available to be read, and entity - /// header sections are expected to fit within a single TCP buffer. - /// </para> - /// </remarks> - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - private HttpStatusCode ParseRequest(ITransportContext transport, HttpContext ctx) - { - //Init parser - TransportReader reader = new (transport.ConnectionStream, ctx.RequestBuffer, Config.HttpEncoding, HeaderLineTermination); - - try - { - Span<char> lineBuf = ctx.RequestBuffer.CharBuffer; - - Http11ParseExtensions.Http1ParseState parseState = new(); - - //Parse the request line - HttpStatusCode code = ctx.Request.Http1ParseRequestLine(ref parseState, ref reader, in lineBuf); - - if (code > 0) - { - return code; - } - //Parse the headers - code = ctx.Request.Http1ParseHeaders(ref parseState, ref reader, Config, in lineBuf); - if (code > 0) - { - return code; - } - //Prepare entity body for request - code = ctx.Request.Http1PrepareEntityBody(ref parseState, ref reader, Config); - if (code > 0) - { - return code; - } - //Success! - return 0; - } - //Catch exahusted buffer request - catch (OutOfMemoryException) - { - return HttpStatusCode.RequestHeaderFieldsTooLarge; - } - catch (UriFormatException) - { - return HttpStatusCode.BadRequest; - } - } - - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - private async ValueTask<ERRNO> ProcessRequestAsync(HttpContext context, HttpStatusCode status) - { - //Check status - if (status != 0) - { - /* - * If the status of the parsing was not successfull the transnport is considered - * an unknowns state and could still have data which could corrupt communications - * or worse, contatin an attack. I am choosing to drop the transport and close the - * connection if parsing the request fails - */ - //Close the connection when we exit - context.Response.Headers[HttpResponseHeader.Connection] = "closed"; - //Return status code, if the the expect header was set, return expectation failed, otherwise return the result status code - context.Respond(context.Request.Expect ? HttpStatusCode.ExpectationFailed : status); - //exit and close connection (default result will close the context) - return false; - } - //We only support version 1 and 1/1 - if ((context.Request.HttpVersion & (HttpVersion.Http11 | HttpVersion.Http1)) == 0) - { - //Close the connection when we exit - context.Response.Headers[HttpResponseHeader.Connection] = "closed"; - context.Respond(HttpStatusCode.HttpVersionNotSupported); - return false; - } - //Check open connection count (not super accurate, or might not be atomic) - if (OpenConnectionCount > Config.MaxOpenConnections) - { - //Close the connection and return 503 - context.Response.Headers[HttpResponseHeader.Connection] = "closed"; - context.Respond(HttpStatusCode.ServiceUnavailable); - return false; - } - - //Store keepalive value from request, and check if keepalives are enabled by the configuration - bool keepalive = context.Request.KeepAlive & Config.ConnectionKeepAlive > TimeSpan.Zero; - - //Set connection header (only for http1 and 1.1) - if (keepalive) - { - context.Response.Headers[HttpResponseHeader.Connection] = "keep-alive"; - context.Response.Headers[HttpResponseHeader.KeepAlive] = KeepAliveTimeoutHeaderValue; - } - else - { - //Set connection closed - context.Response.Headers[HttpResponseHeader.Connection] = "closed"; - } - //Get the server root for the specified location - if (!ServerRoots.TryGetValue(context.Request.Location.DnsSafeHost, out IWebRoot? root) && !ServerRoots.TryGetValue(WILDCARD_KEY, out root)) - { - context.Respond(HttpStatusCode.NotFound); - //make sure control leaves - return keepalive; - } - //check for redirects - if (root.Redirects.TryGetValue(context.Request.Location.LocalPath, out Redirect? r)) - { - //301 - context.Redirect301(r.RedirectUrl); - //Return keepalive - return keepalive; - } - //Check the expect header and return an early status code - if (context.Request.Expect) - { - //send a 100 status code - await context.Response.SendEarly100ContinueAsync(); - } - /* - * Initialze the request body state, which may read/buffer the request - * entity body. When doing so, the only exceptions that should be - * generated are IO, OutOfMemory, and Overflow. IOE should - * be raised to the transport as it will only be thrown if the transport - * is in an unusable state. - * - * OOM and Overflow should only be raised if an over-sized entity - * body was allowed to be read in. The Parse method should have guarded - * form data size so oom or overflow would be bugs, and we can let - * them get thrown - */ - await context.Request.InitRequestBodyAsync(Config.FormDataBufferSize, Config.HttpEncoding); - try - { - await ProcessAsync(root, context); - return keepalive; - } - //The user-code requested termination of the connection - catch (TerminateConnectionException tce) - { - //Log the event as a debug so user can see the result - Config.ServerLog.Debug(tce, "User-code requested a connection termination"); - //See if the exception requested an error code response - if (tce.Code > 0) - { - //close response with status code - context.Respond(tce.Code); - } - else - { - //Clear any currently set headers since no response is requested - context.Response.Headers.Clear(); - } - } - return false; - } - - /// <summary> - /// Processes a client connection after pre-processing has completed - /// </summary> - /// <param name="root">The <see cref="IWebRoot"/> to process the event on</param> - /// <param name="ctx">The <see cref="HttpContext"/> to process</param> - /// <returns>A task that resolves when the user-code has completed processing the entity</returns> - /// <exception cref="IOException"></exception> - /// <exception cref="TerminateConnectionException"></exception> - private static async ValueTask ProcessAsync(IWebRoot root, HttpContext ctx) - { - /* - * The event object should be cleared when it is no longer in use, IE before - * this procedure returns. - */ - HttpEvent ev = new (ctx); - try - { - await root.ClientConnectedAsync(ev); - } - //User code requested exit, elevate the exception - catch (TerminateConnectionException) - { - throw; - } - //Transport exception - catch(IOException ioe) when (ioe.InnerException is SocketException) - { - throw; - } - catch (Exception ex) - { - ctx.ParentServer.Config.ServerLog.Warn(ex, "Unhandled exception during application code execution."); - } - finally - { - ev.Clear(); - } - } - - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/IConnectionContext.cs b/Net.Http/src/Core/IConnectionContext.cs deleted file mode 100644 index 2e3ca46..0000000 --- a/Net.Http/src/Core/IConnectionContext.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IConnectionContext.cs -* -* IConnectionContext.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Threading; -using System.Threading.Tasks; - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// A request-response stream oriented connection state - /// </summary> - internal interface IConnectionContext - { - /// <summary> - /// Initializes the context to work with the specified - /// transport context - /// </summary> - /// <param name="tranpsort">A referrence to the transport context to use</param> - void InitializeContext(ITransportContext tranpsort); - - /// <summary> - /// Signals the context that it should prepare to process a new request - /// for the current transport - /// </summary> - void BeginRequest(); - - /// <summary> - /// Sends any pending data associated with the request to the - /// connection that begun the request - /// </summary> - /// <param name="cancellationToken">A token to cancel the operation</param> - /// <returns>A Task that completes when the response has completed</returns> - Task WriteResponseAsync(CancellationToken cancellationToken); - - /// <summary> - /// Signals to the context that it will release any request specific - /// resources - /// </summary> - void EndRequest(); - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/IHttpEvent.cs b/Net.Http/src/Core/IHttpEvent.cs deleted file mode 100644 index ec1dbb5..0000000 --- a/Net.Http/src/Core/IHttpEvent.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IHttpEvent.cs -* -* IHttpEvent.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Collections.Generic; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Contains an http request and session information. - /// </summary> - public interface IHttpEvent - { - /// <summary> - /// Current connection information. (Like "$_SERVER" superglobal in PHP) - /// </summary> - IConnectionInfo Server { get; } - /// <summary> - /// The <see cref="HttpServer"/> that this connection originated from - /// </summary> - HttpServer OriginServer { get; } - - /// <summary> - /// If the request has query arguments they are stored in key value format - /// </summary> - /// <remarks>Keys are case-insensitive</remarks> - IReadOnlyDictionary<string, string> QueryArgs { get; } - /// <summary> - /// If the request body has form data or url encoded arguments they are stored in key value format - /// </summary> - IReadOnlyDictionary<string, string> RequestArgs { get; } - /// <summary> - /// Contains all files upladed with current request - /// </summary> - /// <remarks>Keys are case-insensitive</remarks> - IReadOnlyList<FileUpload> Files { get; } - - /// <summary> - /// Complete the session and respond to user - /// </summary> - /// <param name="code">Status code of operation</param> - /// <exception cref="InvalidOperationException"></exception> - void CloseResponse(HttpStatusCode code); - - /// <summary> - /// Responds to a client with a <see cref="Stream"/> containing data to be sent to user of a given contentType. - /// Runtime will dispose of the stream during closing event - /// </summary> - /// <param name="code">Response status code</param> - /// <param name="type">MIME ContentType of data</param> - /// <param name="stream">Data to be sent to client</param> - /// <exception cref="IOException"></exception> - /// <exception cref="InvalidOperationException"></exception> - void CloseResponse(HttpStatusCode code, ContentType type, Stream stream); - - /// <summary> - /// Responds to a client with an in-memory <see cref="IMemoryResponseReader"/> containing data - /// to be sent to user of a given contentType. - /// </summary> - /// <param name="code">The status code to set</param> - /// <param name="type">The entity content-type</param> - /// <param name="entity">The in-memory response data</param> - /// <exception cref="InvalidOperationException"></exception> - void CloseResponse(HttpStatusCode code, ContentType type, IMemoryResponseReader entity); - - /// <summary> - /// Configures the server to change protocols from HTTP to the specified - /// custom protocol handler. - /// </summary> - /// <param name="protocolHandler">The custom protocol handler</param> - /// <exception cref="ArgumentNullException"></exception> - /// <exception cref="InvalidOperationException"></exception> - void DangerousChangeProtocol(IAlternateProtocol protocolHandler); - - /// <summary> - /// Disables response compression - /// </summary> - void DisableCompression(); - - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/IHttpLifeCycle.cs b/Net.Http/src/Core/IHttpLifeCycle.cs deleted file mode 100644 index 135219d..0000000 --- a/Net.Http/src/Core/IHttpLifeCycle.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IHttpLifeCycle.cs -* -* IHttpLifeCycle.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// Represents a interface of lifecycle hooks that correspond - /// with HTTP lifecycle events. - /// </summary> - internal interface IHttpLifeCycle - { - /// <summary> - /// Raised when the context is being prepare for reuse, - /// "revived from storage" - /// </summary> - void OnPrepare(); - - /// <summary> - /// Raised when the context is being released back to the pool - /// for reuse at a later time - /// </summary> - void OnRelease(); - - /// <summary> - /// Raised when a new request is about to be processed - /// on the current context - /// </summary> - void OnNewRequest(); - - /// <summary> - /// Raised when the request has been processed and the - /// response has been sent. Used to perform per-request - /// cleanup/reset for another request. - /// </summary> - /// <remarks> - /// This method is guarunteed to be called regardless of an http error, this - /// method should not throw exceptions - /// </remarks> - void OnComplete(); - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/IHttpResponseBody.cs b/Net.Http/src/Core/IHttpResponseBody.cs deleted file mode 100644 index aa2dd34..0000000 --- a/Net.Http/src/Core/IHttpResponseBody.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IHttpResponseBody.cs -* -* IHttpResponseBody.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// Represents a rseponse entity body - /// </summary> - internal interface IHttpResponseBody - { - /// <summary> - /// A value that indicates if there is data - /// to send to the client - /// </summary> - bool HasData { get; } - - /// <summary> - /// A value that indicates if response data requires buffering - /// </summary> - bool BufferRequired { get; } - - /// <summary> - /// Writes internal response entity data to the destination stream - /// </summary> - /// <param name="dest">The response stream to write data to</param> - /// <param name="buffer">An optional buffer used to buffer responses</param> - /// <param name="count">The maximum length of the response data to write</param> - /// <param name="token">A token to cancel the operation</param> - /// <returns>A task that resolves when the response is completed</returns> - Task WriteEntityAsync(Stream dest, long count, Memory<byte>? buffer, CancellationToken token); - - /// <summary> - /// Writes internal response entity data to the destination stream - /// </summary> - /// <param name="dest">The response stream to write data to</param> - /// <param name="buffer">An optional buffer used to buffer responses</param> - /// <param name="token">A token to cancel the operation</param> - /// <returns>A task that resolves when the response is completed</returns> - Task WriteEntityAsync(Stream dest, Memory<byte>? buffer, CancellationToken token); - - /// <summary> - /// The length of the content - /// </summary> - long Length { get; } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Request/HttpInputStream.cs b/Net.Http/src/Core/Request/HttpInputStream.cs deleted file mode 100644 index 61d215f..0000000 --- a/Net.Http/src/Core/Request/HttpInputStream.cs +++ /dev/null @@ -1,222 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpInputStream.cs -* -* HttpInputStream.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Buffers; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils; -using VNLib.Utils.IO; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// Specialized stream to allow reading a request entity body with a fixed content length. - /// </summary> - internal sealed class HttpInputStream : Stream - { - private readonly Func<Stream> GetTransport; - - private long ContentLength; - private Stream? InputStream; - private long _position; - - private ISlindingWindowBuffer<byte>? _initalData; - - public HttpInputStream(Func<Stream> getTransport) => GetTransport = getTransport; - - internal void OnComplete() - { - //Dispose the inigial data buffer - _initalData?.Close(); - _initalData = null; - //Remove stream cache copy - InputStream = null; - //Reset position - _position = 0; - //reset content length - ContentLength = 0; - } - - /// <summary> - /// Creates a new input stream object configured to allow reading of the specified content length - /// bytes from the stream and consumes the initial buffer to read data from on initial read calls - /// </summary> - /// <param name="contentLength">The number of bytes to allow being read from the transport or initial buffer</param> - /// <param name="initial">Entity body data captured on initial read</param> - internal void Prepare(long contentLength, ISlindingWindowBuffer<byte>? initial) - { - ContentLength = contentLength; - _initalData = initial; - - //Cache transport - InputStream = GetTransport(); - } - - public override void Close() => throw new NotSupportedException("The HTTP input stream should never be closed!"); - private long Remaining => Math.Max(ContentLength - _position, 0); - public override bool CanRead => true; - public override bool CanSeek => true; - public override bool CanWrite => false; - public override long Length => ContentLength; - public override long Position { get => _position; set { } } - - public override void Flush(){} - - public override int Read(byte[] buffer, int offset, int count) => Read(buffer.AsSpan(offset, count)); - public override int Read(Span<byte> buffer) - { - //Calculate the amount of data that can be read into the buffer - int bytesToRead = (int)Math.Min(buffer.Length, Remaining); - if (bytesToRead == 0) - { - return 0; - } - - //Clamp output buffer size and create buffer writer - ForwardOnlyWriter<byte> writer = new(buffer[..bytesToRead]); - - //See if all data is internally buffered - if (_initalData != null && _initalData.AccumulatedSize > 0) - { - //Read as much as possible from internal buffer - ERRNO read = _initalData.Read(writer.Remaining); - - //Advance writer - writer.Advance(read); - - //Update position - _position += read; - } - - //See if data is still remaining to be read from transport (reamining size is also the amount of data that can be read) - if (writer.RemainingSize > 0) - { - //Read from transport - ERRNO read = InputStream!.Read(writer.Remaining); - - //Update writer position - writer.Advance(read); - - _position += read; - } - - //Return number of bytes written to the buffer - return writer.Written; - } - - public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); - } - public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) - { - //Calculate the amount of data that can be read into the buffer - int bytesToRead = (int)Math.Min(buffer.Length, Remaining); - if (bytesToRead == 0) - { - return 0; - } - - //Clamp output buffer size and create buffer writer - ForwardOnlyMemoryWriter<byte> writer = new(buffer[..bytesToRead]); - - //See if all data is internally buffered - if (_initalData != null && _initalData.AccumulatedSize > 0) - { - //Read as much as possible from internal buffer - ERRNO read = _initalData.Read(writer.Remaining.Span); - - //Advance writer - writer.Advance(read); - - //Update position - _position += read; - } - - //See if data is still remaining to be read from transport (reamining size is also the amount of data that can be read) - if (writer.RemainingSize > 0) - { - //Read from transport - ERRNO read = await InputStream!.ReadAsync(writer.Remaining, cancellationToken).ConfigureAwait(false); - - //Update writer position - writer.Advance(read); - - _position += read; - } - - //Return number of bytes written to the buffer - return writer.Written; - } - - /// <summary> - /// Asynchronously discards all remaining data in the stream - /// </summary> - /// <param name="heap">The heap to alloc buffers from</param> - /// <param name="maxBufferSize">The maxium size of the buffer to allocate</param> - /// <returns>A task that represents the discard operations</returns> - public async ValueTask DiscardRemainingAsync(int maxBufferSize) - { - long remaining = Remaining; - if(remaining == 0) - { - return; - } - //See if all data has already been buffered - if(_initalData != null && remaining <= _initalData.AccumulatedSize) - { - //All data has been buffred, so just clear the buffer - _position = Length; - } - //We must actaully disacrd data from the stream - else - { - //Calcuate a buffer size to allocate (will never be larger than an int) - int bufferSize = (int)Math.Min(remaining, maxBufferSize); - //Alloc a discard buffer to reset the transport - using IMemoryOwner<byte> discardBuffer = CoreBufferHelpers.GetMemory(bufferSize, false); - int read = 0; - do - { - //Read data to the discard buffer until reading is completed - read = await ReadAsync(discardBuffer.Memory, CancellationToken.None).ConfigureAwait(true); - - } while (read != 0); - } - } - - public override long Seek(long offset, SeekOrigin origin) - { - //Ignore seek control - return _position; - } - public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Request/HttpRequest.cs b/Net.Http/src/Core/Request/HttpRequest.cs deleted file mode 100644 index 2410a8f..0000000 --- a/Net.Http/src/Core/Request/HttpRequest.cs +++ /dev/null @@ -1,284 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpRequest.cs -* -* HttpRequest.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Collections.Generic; -using System.Security.Authentication; - -using VNLib.Utils; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - - internal class HttpRequest : IHttpLifeCycle -#if DEBUG - ,IStringSerializeable -#endif - { - public readonly VnWebHeaderCollection Headers; - public readonly Dictionary<string, string> Cookies; - public readonly List<string> Accept; - public readonly List<string> AcceptLanguage; - public readonly HttpRequestBody RequestBody; - - public HttpVersion HttpVersion { get; set; } - public HttpMethod Method { get; set; } - public string? UserAgent { get; set; } - public string? Boundry { get; set; } - public ContentType ContentType { get; set; } - public string? Charset { get; set; } - public Uri Location { get; set; } - public Uri? Origin { get; set; } - public Uri? Referrer { get; set; } - internal bool KeepAlive { get; set; } - public IPEndPoint RemoteEndPoint { get; set; } - public IPEndPoint LocalEndPoint { get; set; } - public SslProtocols EncryptionVersion { get; set; } - public Tuple<long, long>? Range { get; set; } - /// <summary> - /// A value indicating whether the connection contained a request entity body. - /// </summary> - public bool HasEntityBody { get; set; } - /// <summary> - /// A transport stream wrapper that is positioned for reading - /// the entity body from the input stream - /// </summary> - public HttpInputStream InputStream { get; } - /// <summary> - /// A value indicating if the client's request had an Expect-100-Continue header - /// </summary> - public bool Expect { get; set; } - -#nullable disable - public HttpRequest(Func<Stream> getTransport) - { - //Create new collection for headers - Headers = new(); - //Create new collection for request cookies - Cookies = new(); - //New list for accept - Accept = new(); - AcceptLanguage = new(); - //New reusable input stream - InputStream = new(getTransport); - RequestBody = new(); - } - - - public void OnPrepare() - {} - - public void OnRelease() - {} - - public void OnNewRequest() - { - //Set to defaults - ContentType = ContentType.NonSupported; - EncryptionVersion = default; - Method = HttpMethod.NOT_SUPPORTED; - HttpVersion = HttpVersion.NotSupported; - } - - public void OnComplete() - { - //release the input stream - InputStream.OnComplete(); - RequestBody.OnComplete(); - //Make sure headers, cookies, and accept are cleared for reuse - Headers.Clear(); - Cookies.Clear(); - Accept.Clear(); - AcceptLanguage.Clear(); - //Clear request flags - this.Expect = false; - this.KeepAlive = false; - this.HasEntityBody = false; - //We need to clean up object refs - this.Boundry = default; - this.Charset = default; - this.LocalEndPoint = default; - this.Location = default; - this.Origin = default; - this.Referrer = default; - this.RemoteEndPoint = default; - this.UserAgent = default; - this.Range = default; - //We are all set to reuse the instance - } - - -#if DEBUG - public string Compile() - { - //Alloc char buffer for compilation - using UnsafeMemoryHandle<char> buffer = Memory.UnsafeAlloc<char>(16 * 1024, true); - ForwardOnlyWriter<char> writer = new(buffer.Span); - Compile(ref writer); - return writer.ToString(); - } - - public void Compile(ref ForwardOnlyWriter<char> writer) - { - //Request line - writer.Append(Method.ToString()); - writer.Append(" "); - writer.Append(Location?.PathAndQuery); - writer.Append(" HTTP/"); - switch (HttpVersion) - { - case HttpVersion.NotSupported: - writer.Append("Unsuppored Http version"); - break; - case HttpVersion.Http1: - writer.Append("1.0"); - break; - case HttpVersion.Http11: - writer.Append("1.1"); - break; - case HttpVersion.Http2: - writer.Append("2.0"); - break; - case HttpVersion.Http09: - writer.Append("0.9"); - break; - } - writer.Append("\r\n"); - //write host - writer.Append("Host: "); - writer.Append(Location?.Authority); - writer.Append("\r\n"); - - //Write headers - foreach (string header in Headers.Keys) - { - writer.Append(header); - writer.Append(": "); - writer.Append(Headers[header]); - writer.Append("\r\n"); - } - //Write cookies - foreach (string cookie in Cookies.Keys) - { - writer.Append("Cookie: "); - writer.Append(cookie); - writer.Append("="); - writer.Append(Cookies[cookie]); - writer.Append("\r\n"); - } - - //Write accept - if (Accept.Count > 0) - { - writer.Append("Accept: "); - foreach (string accept in Accept) - { - writer.Append(accept); - writer.Append(", "); - } - writer.Append("\r\n"); - } - //Write accept language - if (AcceptLanguage.Count > 0) - { - writer.Append("Accept-Language: "); - foreach (string acceptLanguage in AcceptLanguage) - { - writer.Append(acceptLanguage); - writer.Append(", "); - } - writer.Append("\r\n"); - } - //Write user agent - if (UserAgent != null) - { - writer.Append("User-Agent: "); - writer.Append(UserAgent); - writer.Append("\r\n"); - } - //Write content type - if (ContentType != ContentType.NonSupported) - { - writer.Append("Content-Type: "); - writer.Append(HttpHelpers.GetContentTypeString(ContentType)); - writer.Append("\r\n"); - } - //Write content length - if (ContentType != ContentType.NonSupported) - { - writer.Append("Content-Length: "); - writer.Append(InputStream.Length); - writer.Append("\r\n"); - } - if (KeepAlive) - { - writer.Append("Connection: keep-alive\r\n"); - } - if (Expect) - { - writer.Append("Expect: 100-continue\r\n"); - } - if(Origin != null) - { - writer.Append("Origin: "); - writer.Append(Origin.ToString()); - writer.Append("\r\n"); - } - if (Referrer != null) - { - writer.Append("Referrer: "); - writer.Append(Referrer.ToString()); - writer.Append("\r\n"); - } - writer.Append("from "); - writer.Append(RemoteEndPoint.ToString()); - writer.Append("\r\n"); - writer.Append("Received on "); - writer.Append(LocalEndPoint.ToString()); - //Write end of headers - writer.Append("\r\n"); - } - - public ERRNO Compile(in Span<char> buffer) - { - ForwardOnlyWriter<char> writer = new(buffer); - Compile(ref writer); - return writer.Written; - } - public override string ToString() - { - return Compile(); - } -#else - public override string ToString() - { - return "Request debug output only available when compiled in DEBUG mode"; - } -#endif - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Request/HttpRequestBody.cs b/Net.Http/src/Core/Request/HttpRequestBody.cs deleted file mode 100644 index 824ca24..0000000 --- a/Net.Http/src/Core/Request/HttpRequestBody.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpRequestBody.cs -* -* HttpRequestBody.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Collections.Generic; - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// Represents a higher-level request entity body (query arguments, request body etc) - /// that has been parsed and captured - /// </summary> - internal class HttpRequestBody - { - public readonly List<FileUpload> Uploads; - public readonly Dictionary<string, string> RequestArgs; - public readonly Dictionary<string, string> QueryArgs; - - public HttpRequestBody() - { - Uploads = new(1); - - //Request/query args should not be request sensitive - RequestArgs = new(StringComparer.OrdinalIgnoreCase); - QueryArgs = new(StringComparer.OrdinalIgnoreCase); - } - - /// <summary> - /// Releases all resources used by the current instance - /// </summary> - public void OnComplete() - { - //Only enumerate/clear if file uplaods are present - if (Uploads.Count > 0) - { - //Dispose all initialized files - for (int i = 0; i < Uploads.Count; i++) - { - Uploads[i].Free(); - } - //Emtpy list - Uploads.Clear(); - } - //Clear request args and file uplaods - RequestArgs.Clear(); - QueryArgs.Clear(); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Request/HttpRequestExtensions.cs b/Net.Http/src/Core/Request/HttpRequestExtensions.cs deleted file mode 100644 index 6a93192..0000000 --- a/Net.Http/src/Core/Request/HttpRequestExtensions.cs +++ /dev/null @@ -1,304 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpRequestExtensions.cs -* -* HttpRequestExtensions.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; - -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -using static VNLib.Net.Http.Core.CoreBufferHelpers; - -namespace VNLib.Net.Http.Core -{ - internal static class HttpRequestExtensions - { - public enum CompressionType - { - None, - Gzip, - Deflate, - Brotli - } - - /// <summary> - /// Gets the <see cref="CompressionType"/> that the connection accepts - /// in a default order, or none if not enabled - /// </summary> - /// <param name="request"></param> - /// <returns>A <see cref="CompressionType"/> with a value the connection support</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static CompressionType GetCompressionSupport(this HttpRequest request) - { - string? acceptEncoding = request.Headers[HttpRequestHeader.AcceptEncoding]; - - if (acceptEncoding == null) - { - return CompressionType.None; - } - else if (acceptEncoding.Contains("gzip", StringComparison.OrdinalIgnoreCase)) - { - return CompressionType.Gzip; - } - else if (acceptEncoding.Contains("deflate", StringComparison.OrdinalIgnoreCase)) - { - return CompressionType.Deflate; - } - else if (acceptEncoding.Contains("br", StringComparison.OrdinalIgnoreCase)) - { - return CompressionType.Brotli; - } - else - { - return CompressionType.None; - } - } - - - /// <summary> - /// Tests the connection's origin header against the location URL by authority. - /// An origin matches if its scheme, host, and port match - /// </summary> - /// <returns>true if the origin header was set and does not match the current locations origin</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsCrossOrigin(this HttpRequest Request) - { - return Request.Origin != null - && (!Request.Origin.Authority.Equals(Request.Location.Authority, StringComparison.Ordinal) - || !Request.Origin.Scheme.Equals(Request.Location.Scheme, StringComparison.Ordinal)); - } - /// <summary> - /// Is the current connection a websocket upgrade request handshake - /// </summary> - /// <returns>true if the connection is a websocket upgrade request, false otherwise</returns> - public static bool IsWebSocketRequest(this HttpRequest Request) - { - string? upgrade = Request.Headers[HttpRequestHeader.Upgrade]; - if (!string.IsNullOrWhiteSpace(upgrade) && upgrade.Contains("websocket", StringComparison.OrdinalIgnoreCase)) - { - //This request is a websocket request - //Check connection header - string? connection = Request.Headers[HttpRequestHeader.Connection]; - //Must be a web socket request - return !string.IsNullOrWhiteSpace(connection) && connection.Contains("upgrade", StringComparison.OrdinalIgnoreCase); - } - return false; - } - - /// <summary> - /// Initializes the <see cref="HttpRequest"/> for an incomming connection - /// </summary> - /// <param name="server"></param> - /// <param name="ctx">The <see cref="TransportEventContext"/> to attach the request to</param> - /// <param name="defaultHttpVersion">The default http version</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Initialize(this HttpRequest server, ITransportContext ctx, HttpVersion defaultHttpVersion) - { - server.LocalEndPoint = ctx.LocalEndPoint; - server.RemoteEndPoint = ctx.RemoteEndpoint; - server.EncryptionVersion = ctx.SslVersion; - //Set to default http version so the response can be configured properly - server.HttpVersion = defaultHttpVersion; - } - - - /// <summary> - /// Initializes the <see cref="HttpRequest.RequestBody"/> for the current request - /// </summary> - /// <param name="Request"></param> - /// <param name="maxBufferSize">The maxium buffer size allowed while parsing reqeust body data</param> - /// <param name="encoding">The request data encoding for url encoded or form data bodies</param> - /// <exception cref="IOException"></exception> - /// <exception cref="OverflowException"></exception> - /// <exception cref="OutOfMemoryException"></exception> - internal static ValueTask InitRequestBodyAsync(this HttpRequest Request, int maxBufferSize, Encoding encoding) - { - /* - * Parses query parameters from the request location query - */ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void ParseQueryArgs(HttpRequest Request) - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - //Query string parse method - static void QueryParser(ReadOnlySpan<char> queryArgument, HttpRequest Request) - { - //Split spans after the '=' character - ReadOnlySpan<char> key = queryArgument.SliceBeforeParam('='); - ReadOnlySpan<char> value = queryArgument.SliceAfterParam('='); - //Insert into dict - Request.RequestBody.QueryArgs[key.ToString()] = value.ToString(); - } - - //if the request has query args, parse and store them - ReadOnlySpan<char> queryString = Request.Location.Query; - if (!queryString.IsEmpty) - { - //trim leading '?' if set - queryString = queryString.TrimStart('?'); - //Split args by '&' - queryString.Split('&', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, QueryParser, Request); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static async ValueTask ParseInputStream(HttpRequest Request, int maxBufferSize, Encoding encoding) - { - /* - * Reads all available data from the request input stream - * If the stream size is smaller than a TCP buffer size, will complete synchronously - */ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static ValueTask<VnString> ReadInputStreamAsync(HttpRequest Request, int maxBufferSize, Encoding encoding) - { - //Calculate a largest available buffer to read the entire stream or up to the maximum buffer size - int bufferSize = (int)Math.Min(Request.InputStream.Length, maxBufferSize); - //Read the stream into a vnstring - return VnString.FromStreamAsync(Request.InputStream, encoding, HttpPrivateHeap, bufferSize); - } - /* - * SpanSplit callback function for storing UrlEncoded request entity - * bodies in key-value pairs and writing them to the - */ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void UrlEncodedSplitCb(ReadOnlySpan<char> kvArg, HttpRequest Request) - { - //Get key side of agument (or entire argument if no value is set) - ReadOnlySpan<char> key = kvArg.SliceBeforeParam('='); - ReadOnlySpan<char> value = kvArg.SliceAfterParam('='); - //trim, allocate strings, and store in the request arg dict - Request.RequestBody.RequestArgs[key.TrimCRLF().ToString()] = value.TrimCRLF().ToString(); - } - - /* - * Parses a Form-Data content type request entity body and stores those arguments in - * Request uploads or request args - */ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void FormDataBodySplitCb(ReadOnlySpan<char> formSegment, ValueTuple<HttpRequestBody, Encoding> state) - { - //Form data arguments - string? DispType = null, Name = null, FileName = null; - ContentType ctHeaderVal = ContentType.NonSupported; - //Get sliding window for parsing data - ForwardOnlyReader<char> reader = new(formSegment.TrimCRLF()); - //Read content headers - do - { - //Get the index of the next crlf - int index = reader.Window.IndexOf(HttpHelpers.CRLF); - //end of headers - if (index < 1) - { - break; - } - //Get header data - ReadOnlySpan<char> header = reader.Window[..index]; - //Split header at colon - int colon = header.IndexOf(':'); - //If no data is available after the colon the header is not valid, so move on to the next body - if (colon < 1) - { - return; - } - //Hash the header value into a header enum - HttpRequestHeader headerType = HttpHelpers.GetRequestHeaderEnumFromValue(header[..colon]); - //get the header value - ReadOnlySpan<char> headerValue = header[(colon + 1)..]; - //Check for content dispositon header - if (headerType == HttpHelpers.ContentDisposition) - { - //Parse the content dispostion - HttpHelpers.ParseDisposition(headerValue, out DispType, out Name, out FileName); - } - //Check for content type - else if (headerType == HttpRequestHeader.ContentType) - { - //The header value for content type should be an MIME content type - ctHeaderVal = HttpHelpers.GetContentType(headerValue.Trim().ToString()); - } - //Shift window to the next line - reader.Advance(index + HttpHelpers.CRLF.Length); - } while (true); - //Remaining data should be the body data (will have leading and trailing CRLF characters - //If filename is set, this must be a file - if (!string.IsNullOrWhiteSpace(FileName)) - { - //Store the file in the uploads - state.Item1.Uploads.Add(FileUpload.FromString(reader.Window.TrimCRLF(), state.Item2, FileName, ctHeaderVal)); - } - //Make sure the name parameter was set and store the message body as a string - else if (!string.IsNullOrWhiteSpace(Name)) - { - //String data as body - state.Item1.RequestArgs[Name] = reader.Window.TrimCRLF().ToString(); - } - } - - switch (Request.ContentType) - { - //CT not supported, dont read it - case ContentType.NonSupported: - break; - case ContentType.UrlEncoded: - //Create a vnstring from the message body and parse it (assuming url encoded bodies are small so a small stack buffer will be fine) - using (VnString urlbody = await ReadInputStreamAsync(Request, maxBufferSize, encoding)) - { - //Get the body as a span, and split the 'string' at the & character - urlbody.AsSpan().Split('&', StringSplitOptions.RemoveEmptyEntries, UrlEncodedSplitCb, Request); - } - break; - case ContentType.MultiPart: - //Make sure we have a boundry specified - if (string.IsNullOrWhiteSpace(Request.Boundry)) - { - break; - } - //Read all data from stream into string - using (VnString body = await ReadInputStreamAsync(Request, maxBufferSize, encoding)) - { - //Split the body as a span at the boundries - body.AsSpan().Split($"--{Request.Boundry}", StringSplitOptions.RemoveEmptyEntries, FormDataBodySplitCb, (Request.RequestBody, encoding)); - } - break; - //Default case is store as a file - default: - //add upload - Request.RequestBody.Uploads.Add(new(Request.InputStream, string.Empty, Request.ContentType, false)); - break; - } - } - - //Parse query - ParseQueryArgs(Request); - - //Decode requests from body - return !Request.HasEntityBody ? ValueTask.CompletedTask : ParseInputStream(Request, maxBufferSize, encoding); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs b/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs deleted file mode 100644 index b37b78b..0000000 --- a/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs +++ /dev/null @@ -1,533 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: Http11ParseExtensions.cs -* -* Http11ParseExtensions.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Linq; -using System.Collections.Generic; -using System.Security.Authentication; -using System.Runtime.CompilerServices; - -using VNLib.Utils; -using VNLib.Utils.IO; -using VNLib.Utils.Logging; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - - internal static class Http11ParseExtensions - { - - /// <summary> - /// Stores the state of an HTTP/1.1 parsing operation - /// </summary> - public ref struct Http1ParseState - { - internal UriBuilder? Location; - internal bool IsAbsoluteRequestUrl; - internal long ContentLength; - } - - - /// <summary> - /// Reads the first line from the transport stream using the specified buffer - /// and parses the HTTP request line components: Method, resource, Http Version - /// </summary> - /// <param name="Request"></param> - /// <param name="reader">The reader to read lines from the transport</param> - /// <param name="parseState">The HTTP1 parsing state</param> - /// <param name="lineBuf">The buffer to use when parsing the request data</param> - /// <returns>0 if the request line was successfully parsed, a status code if the request could not be processed</returns> - /// <exception cref="UriFormatException"></exception> - [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] - public static HttpStatusCode Http1ParseRequestLine(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, in Span<char> lineBuf) - { - //Locals - ERRNO requestResult; - int index, endloc; - - //Read the start line - requestResult = reader.ReadLine(lineBuf); - //Must be able to parse the verb and location - if (requestResult < 1) - { - //empty request - return (HttpStatusCode)1000; - } - - //true up the request line to actual size - ReadOnlySpan<char> requestLine = lineBuf[..(int)requestResult].Trim(); - //Find the first white space character ("GET / HTTP/1.1") - index = requestLine.IndexOf(' '); - if (index == -1) - { - return HttpStatusCode.BadRequest; - } - - //Decode the verb (function requires the string be the exact characters of the request method) - Request.Method = HttpHelpers.GetRequestMethod(requestLine[0..index]); - //Make sure the method is supported - if (Request.Method == HttpMethod.NOT_SUPPORTED) - { - return HttpStatusCode.MethodNotAllowed; - } - - //location string should be from end of verb to HTTP/ NOTE: Only supports http... this is an http server - endloc = requestLine.LastIndexOf(" HTTP/", StringComparison.OrdinalIgnoreCase); - //Client must specify an http version prepended by a single whitespace(rfc2612) - if (endloc == -1) - { - return HttpStatusCode.HttpVersionNotSupported; - } - - //Try to parse the version and only accept the 3 major versions of http - Request.HttpVersion = HttpHelpers.ParseHttpVersion(requestLine[endloc..]); - //Check to see if the version was parsed succesfully - if (Request.HttpVersion == HttpVersion.NotSupported) - { - //Return not supported - return HttpStatusCode.HttpVersionNotSupported; - } - - //Set keepalive flag if http11 - Request.KeepAlive = Request.HttpVersion == HttpVersion.Http11; - - //Get the location segment from the request line - ReadOnlySpan<char> paq = requestLine[(index + 1)..endloc].TrimCRLF(); - - //Process an absolute uri, - if (paq.Contains("://", StringComparison.Ordinal)) - { - //Convert the location string to a .net string and init the location builder (will perform validation when the Uri propery is used) - parseState.Location = new(paq.ToString()); - parseState.IsAbsoluteRequestUrl = true; - return 0; - } - //Try to capture a realative uri - else if (paq.Length > 0 && paq[0] == '/') - { - //Create a default location uribuilder - parseState.Location = new() - { - //Set a default scheme - Scheme = Request.EncryptionVersion == SslProtocols.None ? Uri.UriSchemeHttp : Uri.UriSchemeHttps, - }; - //Need to manually parse the query string - int q = paq.IndexOf('?'); - //has query? - if (q == -1) - { - parseState.Location.Path = paq.ToString(); - } - //Does have query argument - else - { - //separate the path from the query - parseState.Location.Path = paq[0..q].ToString(); - parseState.Location.Query = paq[(q + 1)..].ToString(); - } - return 0; - } - //Cannot service an unknonw location - return HttpStatusCode.BadRequest; - } - - /// <summary> - /// Reads headers from the transport using the supplied character buffer, and updates the current request - /// </summary> - /// <param name="Request"></param> - /// <param name="parseState">The HTTP1 parsing state</param> - /// <param name="Config">The current server <see cref="HttpConfig"/></param> - /// <param name="reader">The <see cref="VnStreamReader"/> to read lines from the transport</param> - /// <param name="lineBuf">The buffer read data from the transport with</param> - /// <returns>0 if the request line was successfully parsed, a status code if the request could not be processed</returns> - [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] - public static HttpStatusCode Http1ParseHeaders(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, in HttpConfig Config, in Span<char> lineBuf) - { - try - { - int headerCount = 0, colon; - bool hostFound = false; - ERRNO charsRead; - ReadOnlySpan<char> headerName, requestHeaderValue; - - /* - * This loop will read "lines" from the transport/reader buffer as headers - * and store them in the rented character buffer with 0 allocations. - * - * Lines will be read from the transport reader until an empty line is read, - * or an exception occurs. The VnStreamReader class will search for lines - * directly in the binary rather than converting the data then parsing it. - * When a line is parsed, its assumed to be an HTTP header at this point in - * the parsing, and is separated into its key-value pair determined by the - * first ':' character to appear. - * - * The header length will be limited by the size of the character buffer, - * or the reader binary buffer while reading lines. Buffer sizes are fixed - * to the system memory page size. Depending on the encoding the user chooses - * this should not be an issue for most configurations. This strategy is - * most efficient for realtivly small header sizes. - * - * The header's key is hashed by the HttpHelpers class and the hash is used to - * index a lookup table to return its enumeration value which is used in the swtich - * statement to reduce the number of strings added to the request header container. - * This was a major effort to reduce memory and CPU overhead while using the - * WebHeaderCollection .NET class, which I think is still worth using instead of a - * custom header data structure class. - * - * Some case statments are custom HttpRequestHeader enum values via internal casted - * constants to be consistant with he .NET implementation. - */ - do - { - //Read a line until we reach the end of headers, this call will block if end of characters is reached and a new string will be read - charsRead = reader.ReadLine(lineBuf); - - //If the result is less than 1, no line is available (end of headers) or could not be read - if (charsRead < 1) - { - break; - } - - //Header count exceeded or header larger than header buffer size - if (charsRead < 0 || headerCount > Config.MaxRequestHeaderCount) - { - return HttpStatusCode.RequestHeaderFieldsTooLarge; - } - - { - //Get the true size of the read header line as a readonly span - ReadOnlySpan<char> header = lineBuf[..(int)charsRead]; - - /* - * RFC 7230, ignore headers with preceeding whitespace - * - * If the first character is whitespace that is enough to - * ignore the rest of the header - */ - if (header[0] == ' ') - { - //Move on to next header - continue; - } - - //Find the first colon - colon = header.IndexOf(':'); - //No colon was found, this is an invalid string, try to skip it and keep reading - if (colon <= 0) - { - continue; - } - - //Store header and its value (sections before and after colon) - headerName = header[..colon].TrimCRLF(); - requestHeaderValue = header[(colon + 1)..].TrimCRLF(); - } - - //Hash the header key and lookup the request header value - switch (HttpHelpers.GetRequestHeaderEnumFromValue(headerName)) - { - case HttpRequestHeader.Connection: - { - //Update keepalive, if the connection header contains "closed" and with the current value of keepalive - Request.KeepAlive &= !requestHeaderValue.Contains("close", StringComparison.OrdinalIgnoreCase); - //Also store the connecion header into the store - Request.Headers.Add(HttpRequestHeader.Connection, requestHeaderValue.ToString()); - } - break; - case HttpRequestHeader.ContentType: - { - if (!HttpHelpers.TryParseContentType(requestHeaderValue.ToString(), out string? ct, out string? charset, out string? boundry) || ct == null) - { - //Invalid content type header value - return HttpStatusCode.UnsupportedMediaType; - } - Request.Boundry = boundry; - Request.Charset = charset; - //Get the content type enum from mime type - Request.ContentType = HttpHelpers.GetContentType(ct); - } - break; - case HttpRequestHeader.ContentLength: - { - //Content length has already been calculated, ERROR, rfc 7230 - if(parseState.ContentLength > 0) - { - Config.ServerLog.Debug("Message warning, recieved multiple content length headers"); - return HttpStatusCode.BadRequest; - } - - //Only capture positive values, and if length is negative we are supposed to ignore it - if (ulong.TryParse(requestHeaderValue, out ulong len) && len < long.MaxValue) - { - parseState.ContentLength = (long)len; - } - else - { - return HttpStatusCode.BadRequest; - } - - //Request size it too large to service - if (parseState.ContentLength > Config.MaxUploadSize) - { - return HttpStatusCode.RequestEntityTooLarge; - } - } - break; - case HttpRequestHeader.Host: - { - //Set host found flag - hostFound = true; - - //Split the host value by the port parameter - ReadOnlySpan<char> port = requestHeaderValue.SliceAfterParam(':').Trim(); - //Slicing beofre the colon should always provide a useable hostname, so allocate a string for it - string host = requestHeaderValue.SliceBeforeParam(':').Trim().ToString(); - - //Verify that the host is usable - if (Uri.CheckHostName(host) == UriHostNameType.Unknown) - { - return HttpStatusCode.BadRequest; - } - - //Verify that the host matches the host header if absolue uri is set - if (parseState.IsAbsoluteRequestUrl) - { - if (!host.Equals(parseState.Location!.Host, StringComparison.OrdinalIgnoreCase)) - { - return HttpStatusCode.BadRequest; - } - } - - //store the host value - parseState.Location!.Host = host; - - //If the port span is empty, no colon was found or the port is invalid - if (!port.IsEmpty) - { - //try to parse the port number - if (!int.TryParse(port, out int p) || p < 0 || p > ushort.MaxValue) - { - return HttpStatusCode.BadRequest; - } - //Store port - parseState.Location.Port = p; - } - } - break; - case HttpRequestHeader.Cookie: - { - //Local function to break cookie segments into key-value pairs - static void AddCookiesCallback(ReadOnlySpan<char> cookie, Dictionary<string, string> cookieContainer) - { - //Get the name parameter and alloc a string - string name = cookie.SliceBeforeParam('=').Trim().ToString(); - //Get the value parameter and alloc a string - string value = cookie.SliceAfterParam('=').Trim().ToString(); - //Add the cookie to the dictionary - _ = cookieContainer.TryAdd(name, value); - } - //Split all cookies by ; with trailing whitespace - requestHeaderValue.Split("; ", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries, AddCookiesCallback, Request.Cookies); - } - break; - case HttpRequestHeader.AcceptLanguage: - //Capture accept languages and store in the request accept collection - requestHeaderValue.Split(',', Request.AcceptLanguage, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - break; - case HttpRequestHeader.Accept: - //Capture accept content types and store in request accept collection - requestHeaderValue.Split(',', Request.Accept, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - break; - case HttpRequestHeader.Referer: - { - //Check the referer header and capture its uri instance, it should be absolutely parseable - if (!requestHeaderValue.IsEmpty && Uri.TryCreate(requestHeaderValue.ToString(), UriKind.Absolute, out Uri? refer)) - { - Request.Referrer = refer; - } - } - break; - case HttpRequestHeader.Range: - { - //See if range bytes value has been set - ReadOnlySpan<char> rawRange = requestHeaderValue.SliceAfterParam("bytes=").TrimCRLF(); - //Make sure the bytes parameter is set - if (rawRange.IsEmpty) - { - break; - } - //Get start range - ReadOnlySpan<char> startRange = rawRange.SliceBeforeParam('-'); - //Get end range (empty if no - exists) - ReadOnlySpan<char> endRange = rawRange.SliceAfterParam('-'); - //See if a range end is specified - if (endRange.IsEmpty) - { - //No end range specified, so only range start - if (long.TryParse(startRange, out long start) && start > -1) - { - //Create new range - Request.Range = new(start, -1); - break; - } - } - //Range has a start and end - else if (long.TryParse(startRange, out long start) && long.TryParse(endRange, out long end) && end > -1) - { - //get start and end components from range header - Request.Range = new(start, end); - break; - } - } - //Could not parse start range from header - return HttpStatusCode.RequestedRangeNotSatisfiable; - case HttpRequestHeader.UserAgent: - //Store user-agent - Request.UserAgent = requestHeaderValue.IsEmpty ? string.Empty : requestHeaderValue.TrimCRLF().ToString(); - break; - //Special code for origin header - case HttpHelpers.Origin: - { - //Alloc a string for origin - string origin = requestHeaderValue.ToString(); - //Origin headers should always be absolute address "parsable" - if (Uri.TryCreate(origin, UriKind.Absolute, out Uri? org)) - { - Request.Origin = org; - } - } - break; - case HttpRequestHeader.Expect: - //Accept 100-continue for the Expect header value - Request.Expect = requestHeaderValue.Equals("100-continue", StringComparison.OrdinalIgnoreCase); - break; - default: - //By default store the header in the request header store - Request.Headers.Add(headerName.ToString(), requestHeaderValue.ToString()); - break; - } - //Increment header count - headerCount++; - } while (true); - - //If request is http11 then host is required - if (Request.HttpVersion == HttpVersion.Http11 && !hostFound) - { - return HttpStatusCode.BadRequest; - } - - } - //Catch an arugment exception within the header add function to cause a bad request result - catch (ArgumentException) - { - return HttpStatusCode.BadRequest; - } - - //Check the final location to make sure data was properly sent - if (string.IsNullOrWhiteSpace(parseState.Location?.Host) - || string.IsNullOrWhiteSpace(parseState.Location.Scheme) - || string.IsNullOrWhiteSpace(parseState.Location.Path) - ) - { - return HttpStatusCode.BadRequest; - } - - //Store the finalized location - Request.Location = parseState.Location.Uri; - - return 0; - } - /// <summary> - /// Prepares the entity body for the current HTTP1 request - /// </summary> - /// <param name="Request"></param> - /// <param name="Config">The current server <see cref="HttpConfig"/></param> - /// <param name="parseState">The HTTP1 parsing state</param> - /// <param name="reader">The <see cref="VnStreamReader"/> to read lines from the transport</param> - /// <returns>0 if the request line was successfully parsed, a status code if the request could not be processed</returns> - [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] - public static HttpStatusCode Http1PrepareEntityBody(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, in HttpConfig Config) - { - //If the content type is multipart, make sure its not too large to ingest - if (Request.ContentType == ContentType.MultiPart && parseState.ContentLength > Config.MaxFormDataUploadSize) - { - return HttpStatusCode.RequestEntityTooLarge; - } - - //Only ingest the rest of the message body if the request is not a head, get, or trace methods - if ((Request.Method & (HttpMethod.GET | HttpMethod.HEAD | HttpMethod.TRACE)) != 0) - { - //Bad format to include a message body with a GET, HEAD, or TRACE request - if (parseState.ContentLength > 0) - { - Config.ServerLog.Debug("Message body received from {ip} with GET, HEAD, or TRACE request, was considered an error and the request was dropped", Request.RemoteEndPoint); - return HttpStatusCode.BadRequest; - } - else - { - //Success! - return 0; - } - } - - //Check for chuncked transfer encoding - ReadOnlySpan<char> transfer = Request.Headers[HttpRequestHeader.TransferEncoding]; - if (!transfer.IsEmpty && transfer.Contains("chunked", StringComparison.OrdinalIgnoreCase)) - { - //Not a valid http version for chunked transfer encoding - if (Request.HttpVersion != HttpVersion.Http11) - { - return HttpStatusCode.BadRequest; - } - /* - * Was a content length also specified? - * This is an issue and is likely an attack. I am choosing not to support - * the HTTP 1.1 standard and will deny reading the rest of the data from the - * transport. - */ - if (parseState.ContentLength > 0) - { - Config.ServerLog.Debug("Possible attempted desync, Content length + chunked encoding specified. RemoteEP: {ip}", Request.RemoteEndPoint); - return HttpStatusCode.BadRequest; - } - - //Handle chunked transfer encoding (not implemented yet) - return HttpStatusCode.NotImplemented; - } - //Make sure non-zero cl header was provided - else if (parseState.ContentLength > 0) - { - //Open a temp buffer to store initial data in - ISlindingWindowBuffer<byte>? initData = reader.GetReminaingData(parseState.ContentLength); - //Setup the input stream and capture the initial data from the reader, and wrap the transport stream to read data directly - Request.InputStream.Prepare(parseState.ContentLength, initData); - Request.HasEntityBody = true; - } - //Success! - return 0; - } - } -} diff --git a/Net.Http/src/Core/Response/ChunkDataAccumulator.cs b/Net.Http/src/Core/Response/ChunkDataAccumulator.cs deleted file mode 100644 index 35c0275..0000000 --- a/Net.Http/src/Core/Response/ChunkDataAccumulator.cs +++ /dev/null @@ -1,228 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ChunkDataAccumulator.cs -* -* ChunkDataAccumulator.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils; -using VNLib.Utils.IO; - -using static VNLib.Net.Http.Core.CoreBufferHelpers; - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// A specialized <see cref="IDataAccumulator{T}"/> for buffering data - /// in Http/1.1 chunks - /// </summary> - internal class ChunkDataAccumulator : IDataAccumulator<byte>, IHttpLifeCycle - { - public const int RESERVED_CHUNK_SUGGESTION = 32; - - private readonly int BufferSize; - private readonly int ReservedSize; - private readonly Encoding Encoding; - private readonly ReadOnlyMemory<byte> CRLFBytes; - - public ChunkDataAccumulator(Encoding encoding, int bufferSize) - { - Encoding = encoding; - CRLFBytes = encoding.GetBytes(HttpHelpers.CRLF); - - ReservedSize = RESERVED_CHUNK_SUGGESTION; - BufferSize = bufferSize; - } - - private byte[]? _buffer; - private int _reservedOffset; - - - ///<inheritdoc/> - public int RemainingSize => _buffer!.Length - AccumulatedSize; - ///<inheritdoc/> - public Span<byte> Remaining => _buffer!.AsSpan(AccumulatedSize); - ///<inheritdoc/> - public Span<byte> Accumulated => _buffer!.AsSpan(_reservedOffset, AccumulatedSize); - ///<inheritdoc/> - public int AccumulatedSize { get; set; } - - private Memory<byte> CompleteChunk => _buffer.AsMemory(_reservedOffset, (AccumulatedSize - _reservedOffset)); - - /// <summary> - /// Attempts to buffer as much data as possible from the specified data - /// </summary> - /// <param name="data">The data to copy</param> - /// <returns>The number of bytes that were buffered</returns> - public ERRNO TryBufferChunk(ReadOnlySpan<byte> data) - { - //Calc data size and reserve space for final crlf - int dataToCopy = Math.Min(data.Length, RemainingSize - CRLFBytes.Length); - - //Write as much data as possible - data[..dataToCopy].CopyTo(Remaining); - //Advance buffer - Advance(dataToCopy); - - //Return number of bytes not written - return dataToCopy; - } - - ///<inheritdoc/> - public void Advance(int count) => AccumulatedSize += count; - - private void InitReserved() - { - //First reserve the chunk window by advancing the accumulator to the size - Advance(ReservedSize); - } - - ///<inheritdoc/> - public void Reset() - { - //zero offsets - _reservedOffset = 0; - AccumulatedSize = 0; - //Init reserved segment - InitReserved(); - } - - /// <summary> - /// Writes the buffered data as a single chunk to the stream asynchronously. The internal - /// state is reset if writing compleded successfully - /// </summary> - /// <param name="output">The stream to write data to</param> - /// <param name="cancellation">A token to cancel the operation</param> - /// <returns>A value task that resolves when the data has been written to the stream</returns> - public async ValueTask FlushAsync(Stream output, CancellationToken cancellation) - { - //Update the chunk size - UpdateChunkSize(); - - //Write trailing chunk delimiter - this.Append(CRLFBytes.Span); - - //write to stream - await output.WriteAsync(CompleteChunk, cancellation); - - //Reset for next chunk - Reset(); - } - - /// <summary> - /// Writes the buffered data as a single chunk to the stream. The internal - /// state is reset if writing compleded successfully - /// </summary> - /// <param name="output">The stream to write data to</param> - /// <returns>A value task that resolves when the data has been written to the stream</returns> - public void Flush(Stream output) - { - //Update the chunk size - UpdateChunkSize(); - - //Write trailing chunk delimiter - this.Append(CRLFBytes.Span); - - //write to stream - output.Write(CompleteChunk.Span); - - //Reset for next chunk - Reset(); - } - - private void UpdateChunkSize() - { - const int CharBufSize = 2 * sizeof(int); - - /* - * Alloc stack buffer to store chunk size hex chars - * the size of the buffer should be at least the number - * of bytes of the max chunk size - */ - Span<char> s = stackalloc char[CharBufSize]; - - //Chunk size is the accumulated size without the reserved segment - int chunkSize = (AccumulatedSize - ReservedSize); - - //format the chunk size - chunkSize.TryFormat(s, out int written, "x"); - - //temp buffer to store encoded data in - Span<byte> encBuf = stackalloc byte[ReservedSize]; - //Encode the chunk size chars - int initOffset = Encoding.GetBytes(s[..written], encBuf); - - Span<byte> encoded = encBuf[..initOffset]; - - /* - * We need to calcuate how to store the encoded buffer directly - * before the accumulated chunk data. - * - * This requires us to properly upshift the reserved buffer to - * the exact size required to store the encoded chunk size - */ - - _reservedOffset = (ReservedSize - (initOffset + CRLFBytes.Length)); - - Span<byte> upshifted = _buffer!.AsSpan(_reservedOffset, ReservedSize); - - //First write the chunk size - encoded.CopyTo(upshifted); - - //Upshift again to write the crlf - upshifted = upshifted[initOffset..]; - - //Copy crlf - CRLFBytes.Span.CopyTo(upshifted); - } - - - public void OnNewRequest() - { - InitReserved(); - } - - public void OnComplete() - { - //Zero offsets - _reservedOffset = 0; - AccumulatedSize = 0; - } - - public void OnPrepare() - { - //Alloc buffer - _buffer = HttpBinBufferPool.Rent(BufferSize); - } - - public void OnRelease() - { - HttpBinBufferPool.Return(_buffer!); - _buffer = null; - } - - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/ChunkedStream.cs b/Net.Http/src/Core/Response/ChunkedStream.cs deleted file mode 100644 index 7a8bebc..0000000 --- a/Net.Http/src/Core/Response/ChunkedStream.cs +++ /dev/null @@ -1,249 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ChunkedStream.cs -* -* ChunkedStream.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -/* -* Provides a Chunked data-encoding stream for writing data-chunks to -* the transport using the basic chunked encoding format from MDN -* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#directives -* -* This stream will buffer entire chunks to avoid multiple writes to the -* transport which can block or at minium cause overhead in context switching -* which should be mostly avoided but cause overhead in copying. Time profiling -* showed nearly equivalent performance for small chunks for synchronous writes. -* -*/ - -using System; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils; -using VNLib.Utils.Memory; - -namespace VNLib.Net.Http.Core -{ - - internal partial class HttpResponse - { - /// <summary> - /// Writes chunked HTTP message bodies to an underlying streamwriter - /// </summary> - private class ChunkedStream : Stream, IHttpLifeCycle - { - private const string LAST_CHUNK_STRING = "0\r\n\r\n"; - - private readonly ReadOnlyMemory<byte> LastChunk; - private readonly ChunkDataAccumulator ChunckAccumulator; - private readonly Func<Stream> GetTransport; - - private Stream? TransportStream; - private bool HadError; - - internal ChunkedStream(Encoding encoding, int chunkBufferSize, Func<Stream> getStream) - { - //Convert and store cached versions of the last chunk bytes - LastChunk = encoding.GetBytes(LAST_CHUNK_STRING); - - //get the min buffer by rounding to the nearest page - int actualBufSize = (chunkBufferSize / 4096 + 1) * 4096; - - //Init accumulator - ChunckAccumulator = new(encoding, actualBufSize); - - GetTransport = getStream; - } - - - public override bool CanRead => false; - public override bool CanSeek => false; - public override bool CanWrite => true; - public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } - public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException("This stream cannot be read from"); - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException("This stream does not support seeking"); - public override void SetLength(long value) => throw new NotSupportedException("This stream does not support seeking"); - public override void Flush() { } - public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - - public override void Write(byte[] buffer, int offset, int count) => Write(new ReadOnlySpan<byte>(buffer, offset, count)); - public override void Write(ReadOnlySpan<byte> chunk) - { - //Only write non-zero chunks - if (chunk.Length <= 0) - { - return; - } - - //Init reader - ForwardOnlyReader<byte> reader = new(in chunk); - try - { - do - { - //try to accumulate the chunk data - ERRNO written = ChunckAccumulator.TryBufferChunk(reader.Window); - - //Not all data was buffered - if (written < reader.WindowSize) - { - //Advance reader - reader.Advance(written); - - //Flush accumulator - ChunckAccumulator.Flush(TransportStream!); - //Continue to buffer / flush as needed - continue; - } - break; - } - while (true); - } - catch - { - HadError = true; - throw; - } - } - - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); - } - - public override async ValueTask WriteAsync(ReadOnlyMemory<byte> chunk, CancellationToken cancellationToken = default) - { - //Only write non-zero chunks - if (chunk.Length <= 0) - { - return; - } - - try - { - //Init reader - ForwardOnlyMemoryReader<byte> reader = new(in chunk); - - do - { - //try to accumulate the chunk data - ERRNO written = ChunckAccumulator.TryBufferChunk(reader.Window.Span); - - //Not all data was buffered - if (written < reader.WindowSize) - { - //Advance reader - reader.Advance(written); - - //Flush accumulator async - await ChunckAccumulator.FlushAsync(TransportStream!, cancellationToken); - //Continue to buffer / flush as needed - continue; - } - break; - } - while (true); - } - catch - { - HadError = true; - throw; - } - } - - public override async ValueTask DisposeAsync() - { - //If write error occured, then do not write the last chunk - if (HadError) - { - return; - } - - //Write remaining data to stream - await ChunckAccumulator.FlushAsync(TransportStream!, CancellationToken.None); - - //Write final chunk - await TransportStream!.WriteAsync(LastChunk, CancellationToken.None); - - //Flush base stream - await TransportStream!.FlushAsync(CancellationToken.None); - } - - protected override void Dispose(bool disposing) => Close(); - - public override void Close() - { - //If write error occured, then do not write the last chunk - if (HadError) - { - return; - } - - //Write remaining data to stream - ChunckAccumulator.Flush(TransportStream!); - - //Write final chunk - TransportStream!.Write(LastChunk.Span); - - //Flush base stream - TransportStream!.Flush(); - } - - - #region Hooks - - public void OnPrepare() - { - ChunckAccumulator.OnPrepare(); - } - - public void OnRelease() - { - ChunckAccumulator.OnRelease(); - } - - public void OnNewRequest() - { - ChunckAccumulator.OnNewRequest(); - - //Get transport stream even if not used - TransportStream = GetTransport(); - } - - public void OnComplete() - { - ChunckAccumulator.OnComplete(); - TransportStream = null; - - //Clear error flag - HadError = false; - } - - #endregion - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/DirectStream.cs b/Net.Http/src/Core/Response/DirectStream.cs deleted file mode 100644 index 957c2a6..0000000 --- a/Net.Http/src/Core/Response/DirectStream.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: DirectStream.cs -* -* DirectStream.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace VNLib.Net.Http.Core -{ - internal partial class HttpResponse - { - private class DirectStream : Stream - { - private Stream? BaseStream; - - public void Prepare(Stream transport) - { - BaseStream = transport; - } - - public override void Write(byte[] buffer, int offset, int count) - { - BaseStream!.Write(buffer, offset, count); - } - - public override void Write(ReadOnlySpan<byte> buffer) - { - BaseStream!.Write(buffer); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return BaseStream!.WriteAsync(buffer, offset, count, cancellationToken); - } - - public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) - { - return BaseStream!.WriteAsync(buffer, cancellationToken); - } - - - public override bool CanRead => false; - public override bool CanSeek => false; - public override bool CanWrite => true; - public override long Length => throw new InvalidOperationException("Stream does not have a length property"); - public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public override int Read(byte[] buffer, int offset, int count) => throw new InvalidOperationException("Stream does not support reading"); - public override long Seek(long offset, SeekOrigin origin) => throw new InvalidOperationException("Stream does not support seeking"); - public override void SetLength(long value) => throw new InvalidOperationException("Stream does not support seeking"); - - public override void Flush() => BaseStream!.Flush(); - public override Task FlushAsync(CancellationToken cancellationToken) => BaseStream!.FlushAsync(cancellationToken); - - - public override void Close() - { - BaseStream = null; - } - - - protected override void Dispose(bool disposing) - { - //Do not call base dispose - Close(); - } - - public override ValueTask DisposeAsync() - { - Close(); - return ValueTask.CompletedTask; - } - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/HeaderDataAccumulator.cs b/Net.Http/src/Core/Response/HeaderDataAccumulator.cs deleted file mode 100644 index 715871f..0000000 --- a/Net.Http/src/Core/Response/HeaderDataAccumulator.cs +++ /dev/null @@ -1,157 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HeaderDataAccumulator.cs -* -* HeaderDataAccumulator.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Text; -using System.Runtime.InteropServices; - -using VNLib.Utils; -using VNLib.Utils.IO; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; -using static VNLib.Net.Http.Core.CoreBufferHelpers; - -namespace VNLib.Net.Http.Core -{ - internal partial class HttpResponse - { - - /// <summary> - /// Specialized data accumulator for compiling response headers - /// </summary> - private class HeaderDataAccumulator : IDataAccumulator<char>, IStringSerializeable, IHttpLifeCycle - { - private readonly int BufferSize; - - public HeaderDataAccumulator(int bufferSize) - { - //Calc correct char buffer size from bin buffer - this.BufferSize = bufferSize * sizeof(char); - } - - /* - * May be an issue but wanted to avoid alloc - * if possible since this is a field in a ref - * type - */ - - private UnsafeMemoryHandle<byte>? _handle; - - public void Advance(int count) - { - //Advance writer - AccumulatedSize += count; - } - - public void WriteLine() => this.Append(HttpHelpers.CRLF); - - public void WriteLine(ReadOnlySpan<char> data) - { - this.Append(data); - WriteLine(); - } - - /*Use bin buffers and cast to char buffer*/ - private Span<char> Buffer => MemoryMarshal.Cast<byte, char>(_handle!.Value.Span); - - public int RemainingSize => Buffer.Length - AccumulatedSize; - public Span<char> Remaining => Buffer[AccumulatedSize..]; - public Span<char> Accumulated => Buffer[..AccumulatedSize]; - public int AccumulatedSize { get; set; } - - /// <summary> - /// Encodes the buffered data and writes it to the stream, - /// attemts to avoid further allocation where possible - /// </summary> - /// <param name="enc"></param> - /// <param name="baseStream"></param> - public void Flush(Encoding enc, Stream baseStream) - { - ReadOnlySpan<char> span = Accumulated; - //Calc the size of the binary buffer - int byteSize = enc.GetByteCount(span); - //See if there is enough room in the current char buffer - if (RemainingSize < (byteSize / sizeof(char))) - { - //We need to alloc a binary buffer to write data to - using UnsafeMemoryHandle<byte> bin = GetBinBuffer(byteSize, false); - //encode data - int encoded = enc.GetBytes(span, bin.Span); - //Write to stream - baseStream.Write(bin.Span[..encoded]); - } - else - { - //Get bin buffer by casting remaining accumulator buffer - Span<byte> bin = MemoryMarshal.Cast<char, byte>(Remaining); - //encode data - int encoded = enc.GetBytes(span, bin); - //Write to stream - baseStream.Write(bin[..encoded]); - } - Reset(); - } - - public void Reset() => AccumulatedSize = 0; - - - - public void OnPrepare() - { - //Alloc buffer - _handle = GetBinBuffer(BufferSize, false); - } - - public void OnRelease() - { - _handle!.Value.Dispose(); - _handle = null; - } - - public void OnNewRequest() - {} - - public void OnComplete() - { - Reset(); - } - - - ///<inheritdoc/> - public string Compile() => Accumulated.ToString(); - ///<inheritdoc/> - public void Compile(ref ForwardOnlyWriter<char> writer) => writer.Append(Accumulated); - ///<inheritdoc/> - public ERRNO Compile(in Span<char> buffer) - { - ForwardOnlyWriter<char> writer = new(buffer); - Compile(ref writer); - return writer.Written; - } - ///<inheritdoc/> - public override string ToString() => Compile(); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/HttpContextExtensions.cs b/Net.Http/src/Core/Response/HttpContextExtensions.cs deleted file mode 100644 index 12702b3..0000000 --- a/Net.Http/src/Core/Response/HttpContextExtensions.cs +++ /dev/null @@ -1,124 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpContextExtensions.cs -* -* HttpContextExtensions.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Runtime.CompilerServices; - -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - /// <summary> - /// Provides extended funcionality of an <see cref="HttpContext"/> - /// </summary> - internal static class HttpContextExtensions - { - /// <summary> - /// Responds to a connection with the given status code - /// </summary> - /// <param name="ctx"></param> - /// <param name="code">The status code to send</param> - /// <exception cref="InvalidOperationException"></exception> - public static void Respond(this HttpContext ctx, HttpStatusCode code) => ctx.Response.SetStatusCode(code); - - /// <summary> - /// Begins a 301 redirection by sending status code and message heaaders to client. - /// </summary> - /// <param name="ctx"></param> - /// <param name="location">Location to direct client to, sets the "Location" header</param> - /// <exception cref="InvalidOperationException"></exception> - public static void Redirect301(this HttpContext ctx, Uri location) - { - ctx.Response.SetStatusCode(HttpStatusCode.MovedPermanently); - //Encode the string for propery http url formatting and set the location header - ctx.Response.Headers[HttpResponseHeader.Location] = location.ToString(); - } - - public const string NO_CACHE_STRING = "no-cache"; - private static readonly string CACHE_CONTROL_VALUE = HttpHelpers.GetCacheString(CacheType.NoCache | CacheType.NoStore); - - /// <summary> - /// Sets CacheControl and Pragma headers to no-cache - /// </summary> - /// <param name="Response"></param> - public static void SetNoCache(this HttpResponse Response) - { - Response.Headers[HttpResponseHeader.Pragma] = NO_CACHE_STRING; - Response.Headers[HttpResponseHeader.CacheControl] = CACHE_CONTROL_VALUE; - } - - /// <summary> - /// Sets the content-range header to the specified parameters - /// </summary> - /// <param name="Response"></param> - /// <param name="start">The content range start</param> - /// <param name="end">The content range end</param> - /// <param name="length">The total content length</param> - public static void SetContentRange(this HttpResponse Response, long start, long end, long length) - { - //Alloc enough space to hold the string - Span<char> buffer = stackalloc char[64]; - ForwardOnlyWriter<char> rangeBuilder = new(buffer); - //Build the range header in this format "bytes <begin>-<end>/<total>" - rangeBuilder.Append("bytes "); - rangeBuilder.Append(start); - rangeBuilder.Append('-'); - rangeBuilder.Append(end); - rangeBuilder.Append('/'); - rangeBuilder.Append(length); - //Print to a string and set the content range header - Response.Headers[HttpResponseHeader.ContentRange] = rangeBuilder.ToString(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ReadOnlyMemory<byte> GetRemainingConstrained(this IMemoryResponseReader reader, int limit) - { - //Calc the remaining bytes - int size = Math.Min(reader.Remaining, limit); - //get segment and slice - return reader.GetMemory()[..size]; - } - - /// <summary> - /// If an end-range is set, returns the remaining bytes up to the end-range, otherwise returns the entire request body length - /// </summary> - /// <param name="body"></param> - /// <param name="range">The data range</param> - /// <returns></returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static long GetResponseLengthWithRange(this IHttpResponseBody body, Tuple<long, long> range) - { - /* - * If end range is defined, then calculate the length of the response - * - * The length is the end range minus the start range plus 1 because range - * is an inclusve value - */ - - return range.Item2 < 0 ? body.Length : Math.Min(body.Length, range.Item2 - range.Item1 + 1); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/HttpContextResponseWriting.cs b/Net.Http/src/Core/Response/HttpContextResponseWriting.cs deleted file mode 100644 index b03363e..0000000 --- a/Net.Http/src/Core/Response/HttpContextResponseWriting.cs +++ /dev/null @@ -1,253 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpContextResponseWriting.cs -* -* HttpContextResponseWriting.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Buffers; -using System.IO.Compression; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; - -namespace VNLib.Net.Http.Core -{ - - internal partial class HttpContext - { - ///<inheritdoc/> - public async Task WriteResponseAsync(CancellationToken cancellation) - { - /* - * If exceptions are raised, the transport is unusable, the connection is terminated, - * and the release method will be called so the context can be reused - */ - - ValueTask discardTask = Request.InputStream.DiscardRemainingAsync(ParentServer.Config.DiscardBufferSize); - - //See if discard is needed - if (ResponseBody.HasData) - { - //Parallel the write and discard - Task response = WriteResponseInternalAsync(cancellation); - Task discard = discardTask.AsTask(); - - await Task.WhenAll(response, discard); - } - else - { - await discardTask; - } - - //Close response - await Response.CloseAsync(); - } - - /// <summary> - /// If implementing application set a response entity body, it is written to the output stream - /// </summary> - /// <param name="token">A token to cancel the operation</param> - private async Task WriteResponseInternalAsync(CancellationToken token) - { - //Adjust/append vary header - Response.Headers.Add(HttpResponseHeader.Vary, "Accept-Encoding"); - - //For head methods - if (Request.Method == HttpMethod.HEAD) - { - if (Request.Range != null) - { - //Get local range - Tuple<long, long> range = Request.Range; - - //Calc constrained content length - long length = ResponseBody.GetResponseLengthWithRange(range); - - //End range is inclusive so substract 1 - long endRange = (range.Item1 + length) - 1; - - //Set content-range header - Response.SetContentRange(range.Item1, endRange, length); - - //Specify what the content length would be - Response.Headers[HttpResponseHeader.ContentLength] = length.ToString(); - - } - else - { - //If the request method is head, do everything but send the body - Response.Headers[HttpResponseHeader.ContentLength] = ResponseBody.Length.ToString(); - } - - //We must send headers here so content length doesnt get overwritten - Response.FlushHeaders(); - } - else - { - Stream outputStream; - /* - * Process range header, data will not be compressed because that would - * require buffering, not a feature yet, and since the range will tell - * us the content length, we can get a direct stream to write to - */ - if (Request.Range != null) - { - //Get local range - Tuple<long, long> range = Request.Range; - - //Calc constrained content length - long length = ResponseBody.GetResponseLengthWithRange(range); - - //End range is inclusive so substract 1 - long endRange = (range.Item1 + length) - 1; - - //Set content-range header - Response.SetContentRange(range.Item1, endRange, length); - - //Get the raw output stream and set the length to the number of bytes - outputStream = Response.GetStream(length); - - await WriteEntityDataAsync(outputStream, length, token); - } - else - { - //Determine if compression should be used - bool compressionDisabled = - //disabled because app code disabled it - ContextFlags.IsSet(COMPRESSION_DISABLED_MSK) - //Disabled because too large or too small - || ResponseBody.Length >= ParentServer.Config.CompressionLimit - || ResponseBody.Length < ParentServer.Config.CompressionMinimum - //Disabled because lower than http11 does not support chunked encoding - || Request.HttpVersion < HttpVersion.Http11; - - //Get first compression method or none if disabled - HttpRequestExtensions.CompressionType ct = compressionDisabled ? HttpRequestExtensions.CompressionType.None : Request.GetCompressionSupport(); - - switch (ct) - { - case HttpRequestExtensions.CompressionType.Gzip: - { - //Specify gzip encoding (using chunked encoding) - Response.Headers[HttpResponseHeader.ContentEncoding] = "gzip"; - //get the chunked output stream - Stream chunked = Response.GetStream(); - //Use chunked encoding and send data as its written - outputStream = new GZipStream(chunked, ParentServer.Config.CompressionLevel, false); - } - break; - case HttpRequestExtensions.CompressionType.Deflate: - { - //Specify gzip encoding (using chunked encoding) - Response.Headers[HttpResponseHeader.ContentEncoding] = "deflate"; - //get the chunked output stream - Stream chunked = Response.GetStream(); - //Use chunked encoding and send data as its written - outputStream = new DeflateStream(chunked, ParentServer.Config.CompressionLevel, false); - } - break; - case HttpRequestExtensions.CompressionType.Brotli: - { - //Specify Brotli encoding (using chunked encoding) - Response.Headers[HttpResponseHeader.ContentEncoding] = "br"; - //get the chunked output stream - Stream chunked = Response.GetStream(); - //Use chunked encoding and send data as its written - outputStream = new BrotliStream(chunked, ParentServer.Config.CompressionLevel, false); - } - break; - //Default is no compression - case HttpRequestExtensions.CompressionType.None: - default: - //Since we know how long the response will be, we can submit it now (see note above for same issues) - outputStream = Response.GetStream(ResponseBody.Length); - break; - } - - //Write entity to output - await WriteEntityDataAsync(outputStream, token); - } - } - } - - private async Task WriteEntityDataAsync(Stream outputStream, CancellationToken token) - { - try - { - //Determine if buffer is required - if (ResponseBody.BufferRequired) - { - //Calc a buffer size (always a safe cast since rbs is an integer) - int bufferSize = (int)Math.Min((long)ParentServer.Config.ResponseBufferSize, ResponseBody.Length); - - //Alloc buffer, and dispose when completed - using IMemoryOwner<byte> buffer = CoreBufferHelpers.GetMemory(bufferSize, false); - - //Write response - await ResponseBody.WriteEntityAsync(outputStream, buffer.Memory, token); - } - //No buffer is required, write response directly - else - { - //Write without buffer - await ResponseBody.WriteEntityAsync(outputStream, null, token); - } - } - finally - { - //always dispose output stream - await outputStream.DisposeAsync(); - } - } - - private async Task WriteEntityDataAsync(Stream outputStream, long length, CancellationToken token) - { - try - { - //Determine if buffer is required - if (ResponseBody.BufferRequired) - { - //Calc a buffer size (always a safe cast since rbs is an integer) - int bufferSize = (int)Math.Min((long)ParentServer.Config.ResponseBufferSize, ResponseBody.Length); - - //Alloc buffer, and dispose when completed - using IMemoryOwner<byte> buffer = CoreBufferHelpers.GetMemory(bufferSize, false); - - //Write response - await ResponseBody.WriteEntityAsync(outputStream, length, buffer.Memory, token); - } - //No buffer is required, write response directly - else - { - //Write without buffer - await ResponseBody.WriteEntityAsync(outputStream, length, null, token); - } - } - finally - { - //always dispose output stream - await outputStream.DisposeAsync(); - } - } - } -} diff --git a/Net.Http/src/Core/Response/HttpResponse.cs b/Net.Http/src/Core/Response/HttpResponse.cs deleted file mode 100644 index ab0971d..0000000 --- a/Net.Http/src/Core/Response/HttpResponse.cs +++ /dev/null @@ -1,307 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpResponse.cs -* -* HttpResponse.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -using VNLib.Utils.IO; - -namespace VNLib.Net.Http.Core -{ - internal partial class HttpResponse : IHttpLifeCycle - { - private readonly HashSet<HttpCookie> Cookies; - private readonly HeaderDataAccumulator Writer; - - private readonly DirectStream ReusableDirectStream; - private readonly ChunkedStream ReusableChunkedStream; - private readonly Func<Stream> _getStream; - private readonly Encoding ResponseEncoding; - private readonly Func<HttpVersion> GetVersion; - - private bool HeadersSent; - private bool HeadersBegun; - - private HttpStatusCode _code; - - /// <summary> - /// Response header collection - /// </summary> - public VnWebHeaderCollection Headers { get; } - - public HttpResponse(Encoding encoding, int headerBufferSize, int chunkedBufferSize, Func<Stream> getStream, Func<HttpVersion> getVersion) - { - //Initialize a new header collection and a cookie jar - Headers = new(); - Cookies = new(); - //Create a new reusable writer stream - Writer = new(headerBufferSize); - - _getStream = getStream; - ResponseEncoding = encoding; - - //Create a new chunked stream - ReusableChunkedStream = new(encoding, chunkedBufferSize, getStream); - ReusableDirectStream = new(); - GetVersion = getVersion; - } - - - /// <summary> - /// Sets the status code of the response - /// </summary> - /// <exception cref="InvalidOperationException"></exception> - internal void SetStatusCode(HttpStatusCode code) - { - if (HeadersBegun) - { - throw new InvalidOperationException("Status code has already been sent"); - } - - _code = code; - } - - /// <summary> - /// Adds a new http-cookie to the collection - /// </summary> - /// <param name="cookie">Cookie to add</param> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AddCookie(HttpCookie cookie) => Cookies.Add(cookie); - - /// <summary> - /// Allows sending an early 100-Continue status message to the client - /// </summary> - /// <exception cref="InvalidOperationException"></exception> - internal async Task SendEarly100ContinueAsync() - { - Check(); - //Send a status message with the continue response status - Writer.WriteLine(HttpHelpers.GetResponseString(GetVersion(), HttpStatusCode.Continue)); - //Trailing crlf - Writer.WriteLine(); - //get base stream - Stream bs = _getStream(); - //Flush writer to stream (will reset the buffer) - Writer.Flush(ResponseEncoding, bs); - //Flush the base stream - await bs.FlushAsync(); - } - - /// <summary> - /// Sends the status message and all available headers to the client. - /// Headers set after method returns will be sent when output stream is requested or scope exits - /// </summary> - /// <exception cref="OutOfMemoryException"></exception> - /// <exception cref="InvalidOperationException"></exception> - public void FlushHeaders() - { - Check(); - //If headers havent been sent yet, start with status code - if (!HeadersBegun) - { - //write status code first - Writer.WriteLine(HttpHelpers.GetResponseString(GetVersion(), _code)); - - //Write the date to header buffer - Writer.Append("Date: "); - Writer.Append(DateTimeOffset.UtcNow, "R"); - Writer.WriteLine(); - //Set begun flag - HeadersBegun = true; - } - //Write headers - for (int i = 0; i < Headers.Count; i++) - { - Writer.Append(Headers.Keys[i]); //Write header key - Writer.Append(": "); //Write separator - Writer.WriteLine(Headers[i]); //Write the header value - } - //Remove writen headers - Headers.Clear(); - //Write cookies if any are set - if (Cookies.Count > 0) - { - //Write cookies if any have been set - foreach (HttpCookie cookie in Cookies) - { - Writer.Append("Set-Cookie: "); - Writer.Append(in cookie); - Writer.WriteLine(); - } - //Clear all current cookies - Cookies.Clear(); - } - } - private void EndFlushHeaders(Stream transport) - { - //Sent all available headers - FlushHeaders(); - //Last line to end headers - Writer.WriteLine(); - - //Flush writer - Writer.Flush(ResponseEncoding, transport); - //Update sent headers - HeadersSent = true; - } - - /// <summary> - /// Gets a stream for writing data of a specified length directly to the client - /// </summary> - /// <param name="ContentLength"></param> - /// <returns>A <see cref="Stream"/> configured for writing data to client</returns> - /// <exception cref="OutOfMemoryException"></exception> - /// <exception cref="InvalidOperationException"></exception> - public Stream GetStream(long ContentLength) - { - Check(); - //Add content length header - Headers[HttpResponseHeader.ContentLength] = ContentLength.ToString(); - //End sending headers so the user can write to the ouput stream - Stream transport = _getStream(); - EndFlushHeaders(transport); - - //Init direct stream - ReusableDirectStream.Prepare(transport); - - //Return the direct stream - return ReusableDirectStream; - } - - /// <summary> - /// Sets up the client for chuncked encoding and gets a stream that allows for chuncks to be sent. User must call dispose on stream when done writing data - /// </summary> - /// <returns><see cref="Stream"/> supporting chunked encoding</returns> - /// <exception cref="OutOfMemoryException"></exception> - /// <exception cref="InvalidOperationException"></exception> - public Stream GetStream() - { -#if DEBUG - if (GetVersion() != HttpVersion.Http11) - { - throw new InvalidOperationException("Chunked transfer encoding is not acceptable for this http version"); - } -#endif - Check(); - //Set encoding type to chunked with user-defined compression - Headers[HttpResponseHeader.TransferEncoding] = "chunked"; - //End sending headers so the user can write to the ouput stream - Stream transport = _getStream(); - EndFlushHeaders(transport); - - //Return the reusable stream - return ReusableChunkedStream; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void Check() - { - if (HeadersSent) - { - throw new InvalidOperationException("Headers have already been sent!"); - } - } - - /// <summary> - /// Finalzies the response to a client by sending all available headers if - /// they have not been sent yet - /// </summary> - /// <exception cref="OutOfMemoryException"></exception> - internal async ValueTask CloseAsync() - { - //If headers havent been sent yet, send them and there must be no content - if (!HeadersBegun) - { - //RFC 7230, length only set on 200 + but not 204 - if ((int)_code >= 200 && (int)_code != 204) - { - //If headers havent been sent by this stage there is no content, so set length to 0 - Headers[HttpResponseHeader.ContentLength] = "0"; - } - //Flush transport - Stream transport = _getStream(); - EndFlushHeaders(transport); - //Flush transport - await transport.FlushAsync(); - } - //Headers have been started but not finished yet - else if (!HeadersSent) - { - //RFC 7230, length only set on 200 + but not 204 - if ((int)_code >= 200 && (int)_code != 204) - { - //If headers havent been sent by this stage there is no content, so set length to 0 - Headers[HttpResponseHeader.ContentLength] = "0"; - } - //If headers arent done sending yet, conclude headers - Stream transport = _getStream(); - EndFlushHeaders(transport); - //Flush transport - await transport.FlushAsync(); - } - } - - - public void OnPrepare() - { - //Propagate all child lifecycle hooks - Writer.OnPrepare(); - ReusableChunkedStream.OnPrepare(); - } - - public void OnRelease() - { - Writer.OnRelease(); - ReusableChunkedStream.OnRelease(); - } - - public void OnNewRequest() - { - //Default to okay status code - _code = HttpStatusCode.OK; - - Writer.OnNewRequest(); - ReusableChunkedStream.OnNewRequest(); - } - - public void OnComplete() - { - //Clear headers and cookies - Headers.Clear(); - Cookies.Clear(); - //Reset status values - HeadersBegun = false; - HeadersSent = false; - - //Call child lifecycle hooks - Writer.OnComplete(); - ReusableChunkedStream.OnComplete(); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/Response/ResponseWriter.cs b/Net.Http/src/Core/Response/ResponseWriter.cs deleted file mode 100644 index c9f20b5..0000000 --- a/Net.Http/src/Core/Response/ResponseWriter.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ResponseWriter.cs -* -* ResponseWriter.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -using VNLib.Utils.Extensions; - - -namespace VNLib.Net.Http.Core -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "<Pending>")] - internal sealed class ResponseWriter : IHttpResponseBody, IHttpLifeCycle - { - private Stream? _streamResponse; - private IMemoryResponseReader? _memoryResponse; - - ///<inheritdoc/> - public bool HasData { get; private set; } - - //Buffering is required when a stream is set - bool IHttpResponseBody.BufferRequired => _streamResponse != null; - - ///<inheritdoc/> - public long Length { get; private set; } - - /// <summary> - /// Attempts to set the response body as a stream - /// </summary> - /// <param name="response">The stream response body to read</param> - /// <returns>True if the response entity could be set, false if it has already been set</returns> - internal bool TrySetResponseBody(Stream response) - { - if (HasData) - { - return false; - } - - //Get relative length of the stream, IE the remaning bytes in the stream if position has been modified - Length = (response.Length - response.Position); - //Store ref to stream - _streamResponse = response; - //update has-data flag - HasData = true; - return true; - } - - /// <summary> - /// Attempts to set the response entity - /// </summary> - /// <param name="response">The memory response to set</param> - /// <returns>True if the response entity could be set, false if it has already been set</returns> - internal bool TrySetResponseBody(IMemoryResponseReader response) - { - if (HasData) - { - return false; - } - - //Get length - Length = response.Remaining; - //Store ref to stream - _memoryResponse = response; - //update has-data flag - HasData = true; - return true; - } - - ///<inheritdoc/> - async Task IHttpResponseBody.WriteEntityAsync(Stream dest, long count, Memory<byte>? buffer, CancellationToken token) - { - //Write a sliding window response - if (_memoryResponse != null) - { - //Get min value from count/range length - int remaining = (int)Math.Min(count, _memoryResponse.Remaining); - - //Write response body from memory - while (remaining > 0) - { - //Get remaining segment - ReadOnlyMemory<byte> segment = _memoryResponse.GetRemainingConstrained(remaining); - - //Write segment to output stream - await dest.WriteAsync(segment, token); - - int written = segment.Length; - - //Advance by the written ammount - _memoryResponse.Advance(written); - - //Update remaining - remaining -= written; - } - } - else - { - //Buffer is required, and count must be supplied - await _streamResponse!.CopyToAsync(dest, buffer!.Value, count, token); - } - } - - ///<inheritdoc/> - async Task IHttpResponseBody.WriteEntityAsync(Stream dest, Memory<byte>? buffer, CancellationToken token) - { - //Write a sliding window response - if (_memoryResponse != null) - { - //Write response body from memory - while (_memoryResponse.Remaining > 0) - { - //Get segment - ReadOnlyMemory<byte> segment = _memoryResponse.GetMemory(); - - await dest.WriteAsync(segment, token); - - //Advance by - _memoryResponse.Advance(segment.Length); - } - } - else - { - //Buffer is required - await _streamResponse!.CopyToAsync(dest, buffer!.Value, token); - - //Try to dispose the response stream - await _streamResponse!.DisposeAsync(); - - //remove ref - _streamResponse = null; - } - } - - ///<inheritdoc/> - void IHttpLifeCycle.OnPrepare() - {} - - ///<inheritdoc/> - void IHttpLifeCycle.OnRelease() - {} - - ///<inheritdoc/> - void IHttpLifeCycle.OnNewRequest() - {} - - public void OnComplete() - { - //Clear has data flag - HasData = false; - Length = 0; - - //Clear rseponse containers - _streamResponse?.Dispose(); - _streamResponse = null; - _memoryResponse?.Close(); - _memoryResponse = null; - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/SharedHeaderReaderBuffer.cs b/Net.Http/src/Core/SharedHeaderReaderBuffer.cs deleted file mode 100644 index 36ebb66..0000000 --- a/Net.Http/src/Core/SharedHeaderReaderBuffer.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: SharedHeaderReaderBuffer.cs -* -* SharedHeaderReaderBuffer.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Runtime.InteropServices; - -using VNLib.Utils.Memory; - - - -namespace VNLib.Net.Http.Core -{ - sealed class SharedHeaderReaderBuffer : IHttpLifeCycle - { - private UnsafeMemoryHandle<byte>? Handle; - - /// <summary> - /// The size of the binary buffer - /// </summary> - public int BinLength { get; } - - private readonly int _bufferSize; - - internal SharedHeaderReaderBuffer(int length) - { - _bufferSize = length + (length * sizeof(char)); - - //Bin buffer is the specified size - BinLength = length; - } - - /// <summary> - /// The binary buffer to store reader information - /// </summary> - public Span<byte> BinBuffer => Handle!.Value.Span[..BinLength]; - - /// <summary> - /// The char buffer to store read characters in - /// </summary> - public Span<char> CharBuffer => MemoryMarshal.Cast<byte, char>(Handle!.Value.Span[BinLength..]); - - public void OnPrepare() - { - //Alloc the shared buffer - Handle = CoreBufferHelpers.GetBinBuffer(_bufferSize, true); - } - - public void OnRelease() - { - //Free buffer - Handle?.Dispose(); - Handle = null; - } - - public void OnNewRequest() - {} - - public void OnComplete() - { - //Zero buffer - Handle!.Value.Span.Clear(); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Core/VnHeaderCollection.cs b/Net.Http/src/Core/VnHeaderCollection.cs deleted file mode 100644 index 8ce3c88..0000000 --- a/Net.Http/src/Core/VnHeaderCollection.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: VnHeaderCollection.cs -* -* VnHeaderCollection.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Collections.Generic; - -namespace VNLib.Net.Http.Core -{ - internal sealed class VnHeaderCollection : IHeaderCollection - { - private VnWebHeaderCollection _RequestHeaders; - private VnWebHeaderCollection _ResponseHeaders; - - - IEnumerable<KeyValuePair<string, string>> IHeaderCollection.RequestHeaders => _RequestHeaders!; - - IEnumerable<KeyValuePair<string, string>> IHeaderCollection.ResponseHeaders => _ResponseHeaders!; - - internal VnHeaderCollection(HttpContext context) - { - _RequestHeaders = context.Request.Headers; - _ResponseHeaders = context.Response.Headers; - } - - string? IHeaderCollection.this[string index] - { - get => _RequestHeaders[index]; - set => _ResponseHeaders[index] = value; - } - - string IHeaderCollection.this[HttpResponseHeader index] - { - set => _ResponseHeaders[index] = value; - } - - string? IHeaderCollection.this[HttpRequestHeader index] => _RequestHeaders[index]; - - bool IHeaderCollection.HeaderSet(HttpResponseHeader header) => !string.IsNullOrEmpty(_ResponseHeaders[header]); - - bool IHeaderCollection.HeaderSet(HttpRequestHeader header) => !string.IsNullOrEmpty(_RequestHeaders[header]); - - void IHeaderCollection.Append(HttpResponseHeader header, string? value) => _ResponseHeaders.Add(header, value); - - void IHeaderCollection.Append(string header, string? value) => _ResponseHeaders.Add(header, value); - -#nullable disable - internal void Clear() - { - _RequestHeaders = null; - _ResponseHeaders = null; - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Exceptions/ContentTypeException.cs b/Net.Http/src/Exceptions/ContentTypeException.cs deleted file mode 100644 index abff151..0000000 --- a/Net.Http/src/Exceptions/ContentTypeException.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ContentTypeException.cs -* -* ContentTypeException.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Thrown when the application attempts to submit a response to a client - /// when the client does not accept the given content type - /// </summary> - public sealed class ContentTypeUnacceptableException:FormatException - { - public ContentTypeUnacceptableException(string message) : base(message) {} - - public ContentTypeUnacceptableException() - {} - - public ContentTypeUnacceptableException(string message, Exception innerException) : base(message, innerException) - {} - } -}
\ No newline at end of file diff --git a/Net.Http/src/Exceptions/TerminateConnectionException.cs b/Net.Http/src/Exceptions/TerminateConnectionException.cs deleted file mode 100644 index b854b6e..0000000 --- a/Net.Http/src/Exceptions/TerminateConnectionException.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: TerminateConnectionException.cs -* -* TerminateConnectionException.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; - -namespace VNLib.Net.Http -{ - /// <summary> - /// User code may throw this exception to signal the <see cref="HttpServer"/> to drop - /// the transport connection and return an optional status code - /// </summary> - public class TerminateConnectionException : Exception - { - internal HttpStatusCode Code { get; } - - /// <summary> - /// Creates a new instance that terminates the connection without sending a response to the connection - /// </summary> - public TerminateConnectionException() : base(){} - /// <summary> - /// Creates a new instance of the connection exception with an error code to respond to the connection with - /// </summary> - /// <param name="responseCode">The status code to send to the user</param> - public TerminateConnectionException(HttpStatusCode responseCode) - { - this.Code = responseCode; - } - - public TerminateConnectionException(string message) : base(message) - {} - - public TerminateConnectionException(string message, Exception innerException) : base(message, innerException) - {} - } -}
\ No newline at end of file diff --git a/Net.Http/src/FileUpload.cs b/Net.Http/src/FileUpload.cs deleted file mode 100644 index 654d682..0000000 --- a/Net.Http/src/FileUpload.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: FileUpload.cs -* -* FileUpload.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Text; - -using VNLib.Utils.IO; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -using static VNLib.Net.Http.Core.CoreBufferHelpers; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Represents an file that was received as an entity body, either using Multipart/FormData or as the entity body itself - /// </summary> - public readonly struct FileUpload - { - /// <summary> - /// Content type of uploaded file - /// </summary> - public readonly ContentType ContentType; - /// <summary> - /// Name of file uploaded - /// </summary> - public readonly string FileName; - /// <summary> - /// The file data captured on upload - /// </summary> - public readonly Stream FileData; - - private readonly bool OwnsHandle; - - /// <summary> - /// Allocates a new binary buffer, encodes, and copies the specified data to a new <see cref="FileUpload"/> - /// structure of the specified content type - /// </summary> - /// <param name="data">The string data to copy</param> - /// <param name="dataEncoding">The encoding instance to encode the string data from</param> - /// <param name="filename">The name of the file</param> - /// <param name="ct">The content type of the file data</param> - /// <returns>The <see cref="FileUpload"/> container</returns> - internal static FileUpload FromString(ReadOnlySpan<char> data, Encoding dataEncoding, string filename, ContentType ct) - { - //get number of bytes - int bytes = dataEncoding.GetByteCount(data); - //get a buffer from the HTTP heap - MemoryHandle<byte> buffHandle = HttpPrivateHeap.Alloc<byte>(bytes); - try - { - //Convert back to binary - bytes = dataEncoding.GetBytes(data, buffHandle); - - //Create a new memory stream encapsulating the file data - VnMemoryStream vms = VnMemoryStream.ConsumeHandle(buffHandle, bytes, true); - - //Create new upload wrapper - return new (vms, filename, ct, true); - } - catch - { - //Make sure the hanle gets disposed if there is an error - buffHandle.Dispose(); - throw; - } - } - - /// <summary> - /// Initialzes a new <see cref="FileUpload"/> structure from the specified data - /// and file information. - /// </summary> - /// <param name="data"></param> - /// <param name="filename"></param> - /// <param name="ct"></param> - /// <param name="ownsHandle"></param> - public FileUpload(Stream data, string filename, ContentType ct, bool ownsHandle) - { - FileName = filename; - ContentType = ct; - //Store handle ownership - OwnsHandle = ownsHandle; - //Store the stream - FileData = data; - } - - /// <summary> - /// Releases any memory the current instance holds if it owns the handles - /// </summary> - internal readonly void Free() - { - //Dispose the handle if we own it - if (OwnsHandle) - { - //This should always be synchronous - FileData.Dispose(); - } - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Helpers/AlternateProtocolTransportStreamWrapper.cs b/Net.Http/src/Helpers/AlternateProtocolTransportStreamWrapper.cs deleted file mode 100644 index 88891fb..0000000 --- a/Net.Http/src/Helpers/AlternateProtocolTransportStreamWrapper.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: AlternateProtocolTransportStreamWrapper.cs -* -* AlternateProtocolTransportStreamWrapper.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading.Tasks; - -using VNLib.Utils.IO; - -namespace VNLib.Net.Http.Core -{ - internal class AlternateProtocolTransportStreamWrapper : BackingStream<Stream> - { - public AlternateProtocolTransportStreamWrapper(Stream transport) - { - this.BaseStream = transport; - } - - //Do not allow the caller to dispose the transport stream - protected override void Dispose(bool disposing) - {} - public override ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } - public override void Close() - {} - } -} diff --git a/Net.Http/src/Helpers/ContentType.cs b/Net.Http/src/Helpers/ContentType.cs deleted file mode 100644 index ce7b7ce..0000000 --- a/Net.Http/src/Helpers/ContentType.cs +++ /dev/null @@ -1,1180 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ContentType.cs -* -* ContentType.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -namespace VNLib.Net.Http -{ - /// <summary> - /// Mime content type - /// </summary> - public enum ContentType - { - NonSupported, - MultiPart, - UrlEncoded, - Aab, - Aac, - Aam, - Aas, - Abw, - Ac, - Acc, - Ace, - Acu, - Acutc, - Adp, - Aep, - Afm, - Afp, - Ahead, - Ai, - Aif, - Aifc, - Aiff, - Air, - Ait, - Ami, - Amr, - Apk, - Apng, - Appcache, - Apr, - Arc, - Arj, - Asc, - Asf, - Asm, - Aso, - Asx, - Atc, - Atom, - Atomcat, - Atomsvc, - Atx, - Au, - Avi, - Avif, - Aw, - Azf, - Azs, - Azv, - Azw, - B16, - Bat, - Bcpio, - Bdf, - Bdm, - Bdoc, - Bed, - Bh2, - Binary, - Blb, - Blorb, - Bmi, - Bmml, - Bmp, - Book, - Box, - Boz, - Bpk, - Bsp, - Btif, - Buffer, - Bz, - Bz2, - C, - C11amc, - C11amz, - C4d, - C4f, - C4g, - C4p, - C4u, - Cab, - Caf, - Cap, - Car, - Cat, - Cb7, - Cba, - Cbr, - Cbt, - Cbz, - Cc, - Cco, - Cct, - Ccxml, - Cdbcmsg, - Cdf, - Cdfx, - Cdkey, - Cdmia, - Cdmic, - Cdmid, - Cdmio, - Cdmiq, - Cdx, - Cdxml, - Cdy, - Cer, - Cfs, - Cgm, - Chat, - Chm, - Chrt, - Cif, - Cii, - Cil, - Cjs, - Cla, - Clkk, - Clkp, - Clkt, - Clkw, - Clkx, - Clp, - Cmc, - Cmdf, - Cml, - Cmp, - Cmx, - Cod, - Coffee, - Com, - Conf, - Cpio, - Cpp, - Cpt, - Crd, - Crl, - Crt, - Crx, - Csh, - Csl, - Csml, - Csp, - Css, - Cst, - Csv, - Cu, - Curl, - Cww, - Cxt, - Cxx, - Dae, - Daf, - Dart, - Dataless, - Davmount, - Dbf, - Dbk, - Dcr, - Dcurl, - Dd2, - Ddd, - Ddf, - Dds, - Deb, - Def, - Deploy, - Der, - Dfac, - Dgc, - Dic, - Dir, - Dis, - Dist, - Distz, - Djv, - Djvu, - Dll, - Dmg, - Dmp, - Dms, - Dna, - Doc, - Docm, - Docx, - Dot, - Dotm, - Dotx, - Dp, - Dpg, - Dra, - Drle, - Dsc, - Dssc, - Dtb, - Dtd, - Dts, - Dtshd, - Dump, - Dvb, - Dvi, - Dwd, - Dwf, - Dwg, - Dxf, - Dxp, - Dxr, - Ear, - Ecma, - Edm, - Edx, - Efif, - Ei6, - Elc, - Emf, - Eml, - Emma, - Emz, - Eol, - Eot, - Eps, - Epub, - Es, - Es3, - Esa, - Esf, - Et3, - Etx, - Eva, - Evy, - Exe, - Exi, - Exp, - Exr, - Ext, - Ez, - Ez2, - Ez3, - F, - F4v, - Fortran, - F90, - Fbs, - Fcdt, - Fcs, - Fdf, - Fdt, - Fg5, - Fgd, - Fh, - Fh4, - Fh5, - Fh7, - Fhc, - Fig, - Fits, - Flac, - Fli, - Flo, - Flv, - Flw, - Flx, - Fly, - Fm, - Fnc, - Fo, - For, - Fpx, - Frame, - Fsc, - Fst, - Ftc, - Fti, - Fvt, - Fxp, - Fxpl, - Fzs, - G2w, - G3, - G3w, - Gac, - Gam, - Gbr, - Gca, - Gdl, - Gdoc, - Geo, - Geojson, - Gex, - Ggb, - Ggt, - Ghf, - Gif, - Gim, - Glb, - Gltf, - Gml, - Gmx, - Gnumeric, - Gph, - Gpx, - Gqf, - Gqs, - Gram, - Gramps, - Gre, - Grv, - Grxml, - Gsf, - Gsheet, - Gslides, - Gtar, - Gtm, - Gtw, - Gv, - Gxf, - Gxt, - Gz, - H, - H261, - H263, - H264, - Hal, - Hbci, - Hbs, - Hdd, - Hdf, - Heic, - Heics, - Heif, - Heifs, - Hej2, - Held, - Hh, - Hjson, - Hlp, - Hpgl, - Hpid, - Hps, - Hqx, - Hsj2, - Htc, - Htke, - Htm, - Html, - Hvd, - Hvp, - Hvs, - I2g, - Icc, - Ice, - Icm, - Ico, - Ics, - Ief, - Ifb, - Ifm, - Iges, - Igl, - Igm, - Igs, - Igx, - Iif, - Img, - Imp, - Ims, - Ini, - Ink, - Inkml, - Install, - Iota, - Ipfix, - Ipk, - Irm, - Irp, - Iso, - Itp, - Its, - Ivp, - Ivu, - Jad, - Jade, - Jam, - Jar, - Jardiff, - Java, - Jhc, - Jisp, - Jls, - Jlt, - Jng, - Jnlp, - Joda, - Jp2, - Jpe, - Jpeg, - Jpf, - Jpg, - Jpg2, - Jpgm, - Jpgv, - Jph, - Jpm, - Jpx, - Javascript, - Json, - Json5, - Jsonld, - Jsonml, - Jsx, - Jxr, - Jxra, - Jxrs, - Jxs, - Jxsc, - Jxsi, - Jxss, - Kar, - Karbon, - Kdbx, - Key, - Kfo, - Kia, - Kml, - Kmz, - Kne, - Knp, - Kon, - Kpr, - Kpt, - Kpxx, - Ksp, - Ktr, - Ktx, - Ktx2, - Ktz, - Kwd, - Kwt, - Lasxml, - Latex, - Lbd, - Lbe, - Les, - Less, - Lgr, - Lha, - Link66, - List, - List3820, - Listafp, - Lnk, - Log, - Lostxml, - Lrf, - Lrm, - Ltf, - Lua, - Luac, - Lvp, - Lwp, - Lzh, - M13, - M14, - M1v, - M21, - M2a, - M2v, - M3a, - M3u, - M3u8, - M4a, - M4p, - M4s, - M4u, - M4v, - Ma, - Mads, - Maei, - Mag, - Maker, - Man, - Manifest, - Map, - Mar, - Markdown, - Mathml, - Mb, - Mbk, - Mbox, - Mc1, - Mcd, - Mcurl, - Md, - Mdb, - Mdi, - Mdx, - Me, - Mesh, - Meta4, - Metalink, - Mets, - Mfm, - Mft, - Mgp, - Mgz, - Mid, - Midi, - Mie, - Mif, - Mime, - Mj2, - Mjp2, - Mjs, - Mk3d, - Mka, - Mkd, - Mks, - Mkv, - Mlp, - Mmd, - Mmf, - Mml, - Mmr, - Mng, - Mny, - Mobi, - Mods, - Mov, - Movie, - Mp2, - Mp21, - Mp2a, - Mp3, - Mp4, - Mp4a, - Mp4s, - Mp4v, - Mpc, - Mpd, - Mpe, - Mpeg, - Mpg, - Mpg4, - Mpga, - Mpkg, - Mpm, - Mpn, - Mpp, - Mpt, - Mpy, - Mqy, - Mrc, - Mrcx, - Ms, - Mscml, - Mseed, - Mseq, - Msf, - Msg, - Msh, - Msi, - Msl, - Msm, - Msp, - Msty, - Mtl, - Mts, - Mus, - Musd, - Musicxml, - Mvb, - Mvt, - Mwf, - Mxf, - Mxl, - Mxmf, - Mxml, - Mxs, - Mxu, - N3, - Nb, - Nbp, - Nc, - Ncx, - Nfo, - Ngdat, - Nitf, - Nlu, - Nml, - Nnd, - Nns, - Nnw, - Npx, - Nq, - Nsc, - Nsf, - Nt, - Ntf, - Numbers, - Nzb, - Oa2, - Oa3, - Oas, - Obd, - Obgx, - Obj, - Oda, - Odb, - Odc, - Odf, - Odft, - Odg, - Odi, - Odm, - Odp, - Ods, - Odt, - Oga, - Ogex, - Ogg, - Ogv, - Ogx, - Omdoc, - Onepkg, - Onetmp, - Onetoc, - Onetoc2, - Opf, - Opml, - Oprc, - Opus, - Org, - Osf, - Osfpvg, - Osm, - Otc, - Otf, - Otg, - Oth, - Oti, - Otp, - Ots, - Ott, - Ova, - Ovf, - Owl, - Oxps, - Oxt, - P, - P10, - P12, - P7b, - P7c, - P7m, - P7r, - P7s, - P8, - Pac, - Pages, - Pas, - Paw, - Pbd, - Pbm, - Pcap, - Pcf, - Pcl, - Pclxl, - Pct, - Pcurl, - Pcx, - Pdb, - Pde, - Pdf, - Pem, - Pfa, - Pfb, - Pfm, - Pfr, - Pfx, - Pgm, - Pgn, - Pgp, - Php, - Pic, - Pkg, - Pki, - Pkipath, - Pkpass, - Pl, - Plb, - Plc, - Plf, - Pls, - Pm, - Pml, - Png, - Pnm, - Portpkg, - Pot, - Potm, - Potx, - Ppam, - Ppd, - Ppm, - Pps, - Ppsm, - Ppsx, - Ppt, - Pptm, - Pptx, - Pqa, - Prc, - Pre, - Prf, - Provx, - Ps, - Psb, - Psd, - Psf, - Pskcxml, - Pti, - Ptid, - Pub, - Pvb, - Pwn, - Pya, - Pyv, - Qam, - Qbo, - Qfx, - Qps, - Qt, - Qwd, - Qwt, - Qxb, - Qxd, - Qxl, - Qxt, - Ra, - Ram, - Raml, - Rapd, - Rar, - Ras, - Rdf, - Rdz, - Relo, - Rep, - Res, - Rgb, - Rif, - Rip, - Ris, - Rl, - Rlc, - Rld, - Rm, - Rmi, - Rmp, - Rms, - Rmvb, - Rnc, - Rng, - Roa, - Roff, - Rp9, - Rpm, - Rpss, - Rpst, - Rq, - Rs, - Rsat, - Rsd, - Rsheet, - Rss, - Rtf, - Rtx, - Run, - Rusd, - S, - S3m, - Saf, - Sass, - Sbml, - Sc, - Scd, - Scm, - Scq, - Scs, - Scss, - Scurl, - Sda, - Sdc, - Sdd, - Sdkd, - Sdkm, - Sdp, - Sdw, - Sea, - See, - Seed, - Sema, - Semd, - Semf, - Senmlx, - Sensmlx, - Ser, - Setpay, - Setreg, - Sfs, - Sfv, - Sgi, - Sgl, - Sgm, - Sgml, - Sh, - Shar, - Shex, - Shf, - Shtml, - Sid, - Sieve, - Sig, - Sil, - Silo, - Sis, - Sisx, - Sit, - Sitx, - Siv, - Skd, - Skm, - Skp, - Skt, - Sldm, - Sldx, - Slim, - Slm, - Sls, - Slt, - Sm, - Smf, - Smi, - Smil, - Smv, - Smzip, - Snd, - Snf, - So, - Spc, - Spdx, - Spf, - Spl, - Spot, - Spp, - Spq, - Spx, - Sql, - Src, - Srt, - Sru, - Srx, - Ssdl, - Sse, - Ssf, - Ssml, - St, - Stc, - Std, - Stf, - Sti, - Stk, - Stl, - Stpx, - Stpxz, - Stpz, - Str, - Stw, - Styl, - Stylus, - Sub, - Sus, - Susp, - Sv4cpio, - Sv4crc, - Svc, - Svd, - Svg, - Svgz, - Swa, - Swf, - Swi, - Swidtag, - Sxc, - Sxd, - Sxg, - Sxi, - Sxm, - Sxw, - T, - T3, - T38, - Taglet, - Tao, - Tap, - Tar, - Tcap, - Tcl, - Td, - Teacher, - Tei, - Tex, - Texi, - Texinfo, - Text, - Tfi, - Tfm, - Tfx, - Tga, - Thmx, - Tif, - Tiff, - Tk, - Tmo, - Toml, - Torrent, - Tpl, - Tpt, - Tr, - Tra, - Trig, - Trm, - Ts, - Tsd, - Tsv, - Ttc, - Ttf, - Ttl, - Ttml, - Twd, - Twds, - Txd, - Txf, - Txt, - U32, - U8dsn, - U8hdr, - U8mdn, - U8msg, - Ubj, - Udeb, - Ufd, - Ufdl, - Ulx, - Umj, - Unityweb, - Uoml, - Uri, - Uris, - Urls, - Usdz, - Ustar, - Utz, - Uu, - Uva, - Uvd, - Uvf, - Uvg, - Uvh, - Uvi, - Uvm, - Uvp, - Uvs, - Uvt, - Uvu, - Uvv, - Uvva, - Uvvd, - Uvvf, - Uvvg, - Uvvh, - Uvvi, - Uvvm, - Uvvp, - Uvvs, - Uvvt, - Uvvu, - Uvvv, - Uvvx, - Uvvz, - Uvx, - Uvz, - Vbox, - Vcard, - Vcd, - Vcf, - Vcg, - Vcs, - Vcx, - Vdi, - Vds, - Vhd, - Vis, - Viv, - Vmdk, - Vob, - Vor, - Vox, - Vrml, - Vsd, - Vsf, - Vss, - Vst, - Vsw, - Vtf, - Vtt, - Vtu, - Vxml, - W3d, - Wad, - Wadl, - War, - Wasm, - Wav, - Wax, - Wbmp, - Wbs, - Wbxml, - Wcm, - Wdb, - Wdp, - Weba, - Webapp, - Webm, - Webp, - Wg, - Wgt, - Wks, - Wm, - Wma, - Wmd, - Wmf, - Wml, - Wmlc, - Wmls, - Wmlsc, - Wmv, - Wmx, - Wmz, - Woff, - Woff2, - Wpd, - Wpl, - Wps, - Wqd, - Wri, - Wrl, - Wsc, - Wsdl, - Wspolicy, - Wtb, - Wvx, - X32, - X3d, - X3db, - X3dbz, - X3dv, - X3dvz, - X3dz, - Xaml, - Xap, - Xar, - Xav, - Xbap, - Xbd, - Xbm, - Xca, - Xcs, - Xdf, - Xdm, - Xdp, - Xdssc, - Xdw, - Xel, - Xenc, - Xer, - Xfdf, - Xfdl, - Xht, - Xhtml, - Xhvml, - Xif, - Xla, - Xlam, - Xlc, - Xlf, - Xlm, - Xls, - Xlsb, - Xlsm, - Xlsx, - Xlt, - Xltm, - Xltx, - Xlw, - Xm, - Xml, - Xns, - Xo, - Xop, - Xpi, - Xpl, - Xpm, - Xpr, - Xps, - Xpw, - Xpx, - Xsd, - Xsl, - Xslt, - Xsm, - Xspf, - Xul, - Xvm, - Xvml, - Xwd, - Xyz, - Xz, - Yaml, - Yang, - Yin, - Yml, - Ymp, - Z1, - Z2, - Z3, - Z4, - Z5, - Z6, - Z7, - Z8, - Zaz, - Zip, - Zir, - Zirz, - Zmm, - } -}
\ No newline at end of file diff --git a/Net.Http/src/Helpers/CoreBufferHelpers.cs b/Net.Http/src/Helpers/CoreBufferHelpers.cs deleted file mode 100644 index 5c5d918..0000000 --- a/Net.Http/src/Helpers/CoreBufferHelpers.cs +++ /dev/null @@ -1,188 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: CoreBufferHelpers.cs -* -* CoreBufferHelpers.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -/* - * This class is meant to provide memory helper methods - * as a centralized HTTP local memory api. - * - * Pools and heaps are privatized to help avoid - * leaking sensitive HTTP data across other application - * allocations and help provide memory optimization. - */ - - - -using System; -using System.IO; -using System.Buffers; -using System.Security; -using System.Threading; - -using VNLib.Utils.IO; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http.Core -{ - - /// <summary> - /// Provides memory pools and an internal heap for allocations. - /// </summary> - internal static class CoreBufferHelpers - { - private class InitDataBuffer : ISlindingWindowBuffer<byte> - { - private readonly ArrayPool<byte> pool; - private readonly int size; - - private byte[]? buffer; - - public InitDataBuffer(ArrayPool<byte> pool, int size) - { - this.buffer = pool.Rent(size, true); - this.pool = pool; - this.size = size; - WindowStartPos = 0; - WindowEndPos = 0; - } - - public int WindowStartPos { get; set; } - public int WindowEndPos { get; set; } - Memory<byte> ISlindingWindowBuffer<byte>.Buffer => buffer.AsMemory(0, size); - - public void Advance(int count) - { - WindowEndPos += count; - } - - public void AdvanceStart(int count) - { - WindowStartPos += count; - } - - public void Reset() - { - WindowStartPos = 0; - WindowEndPos = 0; - } - - //Release the buffer back to the pool - void ISlindingWindowBuffer<byte>.Close() - { - pool.Return(buffer!); - buffer = null; - } - } - - /// <summary> - /// An internal HTTP character binary pool for HTTP specific internal buffers - /// </summary> - public static ArrayPool<byte> HttpBinBufferPool { get; } = ArrayPool<byte>.Create(); - /// <summary> - /// An <see cref="IUnmangedHeap"/> used for internal HTTP buffers - /// </summary> - public static IUnmangedHeap HttpPrivateHeap => _lazyHeap.Value; - - private static readonly Lazy<IUnmangedHeap> _lazyHeap = new(Memory.InitializeNewHeapForProcess, LazyThreadSafetyMode.PublicationOnly); - - /// <summary> - /// Alloctes an unsafe block of memory from the internal heap, or buffer pool - /// </summary> - /// <param name="size">The number of elemnts to allocate</param> - /// <param name="zero">A value indicating of the block should be zeroed before returning</param> - /// <returns>A handle to the block of memory</returns> - /// <exception cref="SecurityException"></exception> - /// <exception cref="OutOfMemoryException"></exception> - public static UnsafeMemoryHandle<byte> GetBinBuffer(int size, bool zero) - { - //Calc buffer size to the nearest page size - size = (size / 4096 + 1) * 4096; - - //If rpmalloc lib is loaded, use it - if (Memory.IsRpMallocLoaded) - { - return Memory.Shared.UnsafeAlloc<byte>(size, zero); - } - else if (size > Memory.MAX_UNSAFE_POOL_SIZE) - { - return HttpPrivateHeap.UnsafeAlloc<byte>(size, zero); - } - else - { - return new(HttpBinBufferPool, size, zero); - } - } - - public static IMemoryOwner<byte> GetMemory(int size, bool zero) - { - //Calc buffer size to the nearest page size - size = (size / 4096 + 1) * 4096; - - //If rpmalloc lib is loaded, use it - if (Memory.IsRpMallocLoaded) - { - return Memory.Shared.DirectAlloc<byte>(size, zero); - } - //Avoid locking in heap unless the buffer is too large to alloc array - else if (size > Memory.MAX_UNSAFE_POOL_SIZE) - { - return HttpPrivateHeap.DirectAlloc<byte>(size, zero); - } - else - { - //Convert temp buffer to memory owner - -#pragma warning disable CA2000 // Dispose objects before losing scope - return new VnTempBuffer<byte>(HttpBinBufferPool, size, zero).ToMemoryManager(); -#pragma warning restore CA2000 // Dispose objects before losing scope - } - } - - /// <summary> - /// Gets the remaining data in the reader buffer and prepares a - /// sliding window buffer to read data from - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="reader"></param> - /// <param name="maxContentLength">Maximum content size to clamp the remaining buffer window to</param> - /// <returns></returns> - public static ISlindingWindowBuffer<byte>? GetReminaingData<T>(this ref T reader, long maxContentLength) where T: struct, IVnTextReader - { - //clamp max available to max content length - int available = Math.Clamp(reader.Available, 0, (int)maxContentLength); - if (available <= 0) - { - return null; - } - //Alloc sliding window buffer - ISlindingWindowBuffer<byte> buffer = new InitDataBuffer(HttpBinBufferPool, available); - //Read remaining data - reader.ReadRemaining(buffer.RemainingBuffer.Span); - //Advance the buffer to the end of available data - buffer.Advance(available); - return buffer; - } - - } -} diff --git a/Net.Http/src/Helpers/HelperTypes.cs b/Net.Http/src/Helpers/HelperTypes.cs deleted file mode 100644 index e89ca78..0000000 --- a/Net.Http/src/Helpers/HelperTypes.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HelperTypes.cs -* -* HelperTypes.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; - -namespace VNLib.Net.Http -{ - [Flags] - public enum HttpMethod - { - NOT_SUPPORTED, - GET = 0x01, - POST = 0x02, - PUT = 0x04, - OPTIONS = 0x08, - HEAD = 0x10, - MERGE = 0x20, - COPY = 0x40, - DELETE = 0x80, - PATCH = 0x100, - TRACE = 0x200, - MOVE = 0x400, - LOCK = 0x800 - } - /// <summary> - /// HTTP protocol version - /// </summary> - [Flags] - public enum HttpVersion - { - NotSupported, - Http1 = 0x01, - Http11 = 0x02, - Http2 = 0x04, - Http09 = 0x08 - } - /// <summary> - /// HTTP response entity cache flags - /// </summary> - [Flags] - public enum CacheType - { - Ignore = 0x00, - NoCache = 0x01, - Private = 0x02, - Public = 0x04, - NoStore = 0x08, - Revalidate = 0x10 - } - - /// <summary> - /// Specifies an HTTP cookie SameSite type - /// </summary> - public enum CookieSameSite - { - Lax, None, SameSite - } - - /// <summary> - /// Low level 301 "hard" redirect - /// </summary> - public class Redirect - { - public readonly string Url; - public readonly Uri RedirectUrl; - /// <summary> - /// Quickly redirects a url to another url before sessions are established - /// </summary> - /// <param name="url">Url to redirect on</param> - /// <param name="redirecturl">Url to redirect to</param> - public Redirect(string url, string redirecturl) - { - Url = url; - RedirectUrl = new(redirecturl); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Helpers/HttpHelpers.cs b/Net.Http/src/Helpers/HttpHelpers.cs deleted file mode 100644 index 9cceff1..0000000 --- a/Net.Http/src/Helpers/HttpHelpers.cs +++ /dev/null @@ -1,445 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpHelpers.cs -* -* HttpHelpers.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Collections.Generic; -using System.Text.RegularExpressions; - -using VNLib.Net.Http.Core; -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Provides a set of HTTP helper functions - /// </summary> - public static partial class HttpHelpers - { - /// <summary> - /// Carrage return + line feed characters used within the VNLib.Net.Http namespace to delimit http messages/lines - /// </summary> - public const string CRLF = "\r\n"; - - public const string WebsocketRFC4122Guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - public const string EVENT_STREAM_ACCEPT_TYPE = "text/event-stream"; - - /// <summary> - /// Extended <see cref="HttpRequestHeader"/> for origin header, DO NOT USE IN <see cref="WebHeaderCollection"/> - /// </summary> - internal const HttpRequestHeader Origin = (HttpRequestHeader)42; - /// <summary> - /// Extended <see cref="HttpRequestHeader"/> for Content-Disposition, DO NOT USE IN <see cref="WebHeaderCollection"/> - /// </summary> - internal const HttpRequestHeader ContentDisposition = (HttpRequestHeader)41; - - private static readonly Regex HttpRequestBuilderRegex = new("(?<=[a-z])([A-Z])", RegexOptions.Compiled); - - /* - * Provides a hashable lookup table from a method string's hashcode to output - * an HttpMethod enum value, - */ - - private static readonly IReadOnlyDictionary<int, HttpMethod> MethodHashLookup; - - /* - * Provides a constant lookup table from an MIME http request header string to a .NET - * enum value (with some extra support) - */ - - private static readonly IReadOnlyDictionary<string, HttpRequestHeader> RequestHeaderLookup = new Dictionary<string, HttpRequestHeader>() - { - {"CacheControl", HttpRequestHeader.CacheControl }, - {"Connection", HttpRequestHeader.Connection }, - {"Date", HttpRequestHeader.Date }, - {"Keep-Alive", HttpRequestHeader.KeepAlive }, - {"Pragma", HttpRequestHeader.Pragma }, - {"Trailer", HttpRequestHeader.Trailer }, - {"Transfer-Encoding", HttpRequestHeader.TransferEncoding }, - {"Upgrade", HttpRequestHeader.Upgrade }, - {"Via", HttpRequestHeader.Via }, - {"Warning", HttpRequestHeader.Warning }, - {"Allow", HttpRequestHeader.Allow }, - {"Content-Length", HttpRequestHeader.ContentLength }, - {"Content-Type", HttpRequestHeader.ContentType }, - {"Content-Encoding", HttpRequestHeader.ContentEncoding }, - {"Content-Language", HttpRequestHeader.ContentLanguage }, - {"Content-Location", HttpRequestHeader.ContentLocation }, - {"Content-Md5", HttpRequestHeader.ContentMd5 }, - {"Content-Range", HttpRequestHeader.ContentRange }, - {"Expires", HttpRequestHeader.Expires }, - {"Last-Modified", HttpRequestHeader.LastModified }, - {"Accept", HttpRequestHeader.Accept }, - {"Accept-Charset", HttpRequestHeader.AcceptCharset }, - {"Accept-Encoding", HttpRequestHeader.AcceptEncoding }, - {"Accept-Language", HttpRequestHeader.AcceptLanguage }, - {"Authorization", HttpRequestHeader.Authorization }, - {"Cookie", HttpRequestHeader.Cookie }, - {"Expect", HttpRequestHeader.Expect }, - {"From", HttpRequestHeader.From }, - {"Host", HttpRequestHeader.Host }, - {"IfMatch", HttpRequestHeader.IfMatch }, - {"If-Modified-Since", HttpRequestHeader.IfModifiedSince }, - {"If-None-Match", HttpRequestHeader.IfNoneMatch }, - {"If-Range", HttpRequestHeader.IfRange }, - {"If-Unmodified-Since", HttpRequestHeader.IfUnmodifiedSince }, - {"MaxForwards", HttpRequestHeader.MaxForwards }, - {"Proxy-Authorization", HttpRequestHeader.ProxyAuthorization }, - {"Referer", HttpRequestHeader.Referer }, - {"Range", HttpRequestHeader.Range }, - {"Te", HttpRequestHeader.Te }, - {"Translate", HttpRequestHeader.Translate }, - {"User-Agent", HttpRequestHeader.UserAgent }, - //Custom request headers - { "Content-Disposition", ContentDisposition }, - { "origin", Origin } - }; - - /* - * Provides a lookup table for request header hashcodes (that are hashed in - * the static constructor) to ouput an http request header enum value from - * a header string's hashcode (allows for spans to produce an enum value - * during request parsing) - * - */ - private static readonly IReadOnlyDictionary<int, HttpRequestHeader> RequestHeaderHashLookup; - - /* - * Provides a constant lookup table for http version hashcodes to an http - * version enum value - */ - private static readonly IReadOnlyDictionary<int, HttpVersion> VersionHashLookup = new Dictionary<int, HttpVersion>() - { - { string.GetHashCode("HTTP/0.9", StringComparison.OrdinalIgnoreCase), HttpVersion.Http09 }, - { string.GetHashCode("HTTP/1.0", StringComparison.OrdinalIgnoreCase), HttpVersion.Http1 }, - { string.GetHashCode("HTTP/1.1", StringComparison.OrdinalIgnoreCase), HttpVersion.Http11 }, - { string.GetHashCode("HTTP/2.0", StringComparison.OrdinalIgnoreCase), HttpVersion.Http2 } - }; - - - //Pre-compiled strings for all status codes for http 1, 1.1, and 2 - private static readonly IReadOnlyDictionary<HttpStatusCode, string> V1_STAUTS_CODES; - private static readonly IReadOnlyDictionary<HttpStatusCode, string> V1_1_STATUS_CODES; - private static readonly IReadOnlyDictionary<HttpStatusCode, string> V2_STAUTS_CODES; - - static HttpHelpers() - { - { - //Setup status code dict - Dictionary<HttpStatusCode, string> v1status = new(); - Dictionary<HttpStatusCode, string> v11status = new(); - Dictionary<HttpStatusCode, string> v2status = new(); - //Get all status codes - foreach (HttpStatusCode code in Enum.GetValues<HttpStatusCode>()) - { - //Use a regex to write the status code value as a string - v1status[code] = $"HTTP/1.0 {(int)code} {HttpRequestBuilderRegex.Replace(code.ToString(), " $1")}"; - v11status[code] = $"HTTP/1.1 {(int)code} {HttpRequestBuilderRegex.Replace(code.ToString(), " $1")}"; - v2status[code] = $"HTTP/2.0 {(int)code} {HttpRequestBuilderRegex.Replace(code.ToString(), " $1")}"; - } - //Store as readonly - V1_STAUTS_CODES = v1status; - V1_1_STATUS_CODES = v11status; - V2_STAUTS_CODES = v2status; - } - { - /* - * Http methods are hashed at runtime using the HttpMethod enum - * values, purley for compatability and automation - */ - Dictionary<int, HttpMethod> methods = new(); - //Add all HTTP methods - foreach (HttpMethod method in Enum.GetValues<HttpMethod>()) - { - //Exclude the not supported method - if (method == HttpMethod.NOT_SUPPORTED) - { - continue; - } - //Store method string's hashcode for faster lookups - methods[string.GetHashCode(method.ToString(), StringComparison.OrdinalIgnoreCase)] = method; - } - MethodHashLookup = methods; - } - { - /* - * Pre-compute common headers - */ - Dictionary<int, HttpRequestHeader> requestHeaderHashes = new(); - //Add all HTTP methods - foreach (string headerValue in RequestHeaderLookup.Keys) - { - //Compute the hashcode for the header value - int hashCode = string.GetHashCode(headerValue, StringComparison.OrdinalIgnoreCase); - //Store the http header enum value with the hash-code of the string of said header - requestHeaderHashes[hashCode] = RequestHeaderLookup[headerValue]; - } - RequestHeaderHashLookup = requestHeaderHashes; - } - } - - - /// <summary> - /// Returns an http formatted content type string of a specified content type - /// </summary> - /// <param name="type">Contenty type</param> - /// <returns>Http acceptable string representing a content type</returns> - /// <exception cref="KeyNotFoundException"></exception> - public static string GetContentTypeString(ContentType type) => CtToMime[type]; - /// <summary> - /// Returns the <see cref="ContentType"/> enum value from the MIME string - /// </summary> - /// <param name="type">Content type from request</param> - /// <returns><see cref="ContentType"/> of request, <see cref="ContentType.NonSupported"/> if unknown</returns> - public static ContentType GetContentType(string type) => MimeToCt.GetValueOrDefault(type, ContentType.NonSupported); - //Cache control string using mdn reference - //https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control - /// <summary> - /// Builds a Cache-Control MIME content header from the specified flags - /// </summary> - /// <param name="type">The cache type/mode</param> - /// <param name="maxAge">The max-age (time in seconds) argument</param> - /// <param name="immutable">Sets the immutable argument</param> - /// <returns>The string representation of the Cache-Control header</returns> - public static string GetCacheString(CacheType type, int maxAge = 0, bool immutable = false) - { - //Rent a buffer to write header to - Span<char> buffer = stackalloc char[128]; - //Get buffer writer for cache header - ForwardOnlyWriter<char> sb = new(buffer); - if ((type & CacheType.NoCache) > 0) - { - sb.Append("no-cache, "); - } - if ((type & CacheType.NoStore) > 0) - { - sb.Append("no-store, "); - } - if ((type & CacheType.Public) > 0) - { - sb.Append("public, "); - } - if ((type & CacheType.Private) > 0) - { - sb.Append("private, "); - } - if ((type & CacheType.Revalidate) > 0) - { - sb.Append("must-revalidate, "); - } - if (immutable) - { - sb.Append("immutable, "); - } - sb.Append("max-age="); - sb.Append(maxAge); - return sb.ToString(); - } - /// <summary> - /// Builds a Cache-Control MIME content header from the specified flags - /// </summary> - /// <param name="type">The cache type/mode</param> - /// <param name="maxAge">The max-age argument</param> - /// <param name="immutable">Sets the immutable argument</param> - /// <returns>The string representation of the Cache-Control header</returns> - public static string GetCacheString(CacheType type, TimeSpan maxAge, bool immutable = false) => GetCacheString(type, (int)maxAge.TotalSeconds, immutable); - /// <summary> - /// Returns an enum value of an httpmethod of an http request method string - /// </summary> - /// <param name="smethod">Http acceptable method type string</param> - /// <returns>Request method, <see cref="HttpMethod.NOT_SUPPORTED"/> if method is malformatted or unsupported</returns> - /// <exception cref="ArgumentNullException"></exception> - public static HttpMethod GetRequestMethod(ReadOnlySpan<char> smethod) - { - //Get the hashcode for the method "string" - int hashCode = string.GetHashCode(smethod, StringComparison.OrdinalIgnoreCase); - //run the lookup and return not supported if the method was not found - return MethodHashLookup.GetValueOrDefault(hashCode, HttpMethod.NOT_SUPPORTED); - } - /// <summary> - /// Compares the first 3 bytes of IPV4 ip address or the first 6 bytes of a IPV6. Can be used to determine if the address is local to another address - /// </summary> - /// <param name="first">Address to be compared</param> - /// <param name="other">Address to be comared to first address</param> - /// <returns>True if first 2 bytes of each address match (Big Endian)</returns> - public static bool IsLocalSubnet(this IPAddress first, IPAddress other) - { - if(first.AddressFamily != other.AddressFamily) - { - return false; - } - switch (first.AddressFamily) - { - case AddressFamily.InterNetwork: - { - //Alloc buffers 4 bytes for IPV4 - Span<byte> firstBytes = stackalloc byte[4]; - Span<byte> otherBytes = stackalloc byte[4]; - //Write address's to the buffers - if (first.TryWriteBytes(firstBytes, out _) && other.TryWriteBytes(otherBytes, out _)) - { - //Compare the first 3 bytes of the first address to the second address - return firstBytes.StartsWith(otherBytes[..3]); - } - } - break; - case AddressFamily.InterNetworkV6: - { - //Alloc buffers 8 bytes for IPV6 - Span<byte> firstBytes = stackalloc byte[8]; - Span<byte> otherBytes = stackalloc byte[8]; - //Write address's to the buffers - if (first.TryWriteBytes(firstBytes, out _) && other.TryWriteBytes(otherBytes, out _)) - { - //Compare the first 6 bytes of the first address to the second address - return firstBytes.StartsWith(otherBytes[..6]); - } - } - break; - } - return false; - } - /// <summary> - /// Selects a <see cref="ContentType"/> for a given file extension - /// </summary> - /// <param name="path">Path (including extension) of a file</param> - /// <returns><see cref="ContentType"/> of file. Returns <see cref="ContentType.Binary"/> if extension is unknown</returns> - public static ContentType GetContentTypeFromFile(ReadOnlySpan<char> path) - { - //Get the file's extension - ReadOnlySpan<char> extention = Path.GetExtension(path); - //Trim leading . - extention = extention.Trim('.'); - //If the extension is defined, perform a lookup, otherwise return the default - return ExtensionToCt.GetValueOrDefault(extention.ToString(), ContentType.Binary); - } - /// <summary> - /// Selects a runtime compiled <see cref="string"/> matching the given <see cref="HttpStatusCode"/> and <see cref="HttpVersion"/> - /// </summary> - /// <param name="version">Version of the response string</param> - /// <param name="code">Status code of the response</param> - /// <returns>The HTTP response status line matching the code and version</returns> - public static string GetResponseString(HttpVersion version, HttpStatusCode code) - { - return version switch - { - HttpVersion.Http1 => V1_STAUTS_CODES[code], - HttpVersion.Http2 => V2_STAUTS_CODES[code], - _ => V1_1_STATUS_CODES[code], - }; - } - - /// <summary> - /// Parses the mime Content-Type header value into its sub-components - /// </summary> - /// <param name="header">The Content-Type header value field</param> - /// <param name="ContentType">The mime content type field</param> - /// <param name="Charset">The mime charset</param> - /// <param name="Boundry">The multi-part form boundry parameter</param> - /// <returns>True if parsing the content type succeded, false otherwise</returns> - public static bool TryParseContentType(string header, out string? ContentType, out string? Charset, out string? Boundry) - { - try - { - //Parse content type - System.Net.Mime.ContentType ctype = new(header); - Boundry = ctype.Boundary; - Charset = ctype.CharSet; - ContentType = ctype.MediaType; - return true; - } - catch -//Disable warning for not using the exception, intended behavior -#pragma warning disable ERP022 // Unobserved exception in a generic exception handler. - { - ContentType = Charset = Boundry = null; - //Invalid content type header value - } -#pragma warning restore ERP022 // Unobserved exception in a generic exception handler. - return false; - } - - /// <summary> - /// Parses a standard HTTP Content disposition header into its sub-components, type, name, filename (optional) - /// </summary> - /// <param name="header">The buffer containing the Content-Disposition header value only</param> - /// <param name="type">The mime form type</param> - /// <param name="name">The mime name argument</param> - /// <param name="fileName">The mime filename</param> - public static void ParseDisposition(ReadOnlySpan<char> header, out string? type, out string? name, out string? fileName) - { - //First parameter should be the type argument - type = header.SliceBeforeParam(';').Trim().ToString(); - //Set defaults for name and filename - name = fileName = null; - //get the name parameter - ReadOnlySpan<char> nameSpan = header.SliceAfterParam("name=\""); - if (!nameSpan.IsEmpty) - { - //Capture the name parameter value and trim it up - name = nameSpan.SliceBeforeParam('"').Trim().ToString(); - } - //Check for the filename parameter - ReadOnlySpan<char> fileNameSpan = header.SliceAfterParam("filename=\""); - if (!fileNameSpan.IsEmpty) - { - //Capture the name parameter value and trim it up - fileName = fileNameSpan.SliceBeforeParam('"').Trim().ToString(); - } - } - - /// <summary> - /// Performs a lookup of the specified header name to get the <see cref="HttpRequestHeader"/> enum value - /// </summary> - /// <param name="requestHeaderName">The value of the HTTP request header to compute</param> - /// <returns>The <see cref="HttpRequestHeader"/> enum value of the header, or 255 if not found</returns> - internal static HttpRequestHeader GetRequestHeaderEnumFromValue(ReadOnlySpan<char> requestHeaderName) - { - //Compute the hashcode from the header name - int hashcode = string.GetHashCode(requestHeaderName, StringComparison.OrdinalIgnoreCase); - //perform lookup - return RequestHeaderHashLookup.GetValueOrDefault(hashcode, (HttpRequestHeader)255); - } - - /// <summary> - /// Gets the <see cref="HttpVersion"/> enum value from the version string - /// </summary> - /// <param name="httpVersion">The http header version string</param> - /// <returns>The <see cref="HttpVersion"/> enum value, or - /// <see cref="HttpVersion.NotSupported"/> if the version could not be - /// determined - /// </returns> - public static HttpVersion ParseHttpVersion(ReadOnlySpan<char> httpVersion) - { - //Get the hashcode for the http version "string" - int hashCode = string.GetHashCode(httpVersion.Trim(), StringComparison.OrdinalIgnoreCase); - //return the version that matches the hashcode, or return unsupported of not found - return VersionHashLookup.GetValueOrDefault(hashCode, HttpVersion.NotSupported); - } - } -}
\ No newline at end of file diff --git a/Net.Http/src/Helpers/MimeLookups.cs b/Net.Http/src/Helpers/MimeLookups.cs deleted file mode 100644 index 03bc59d..0000000 --- a/Net.Http/src/Helpers/MimeLookups.cs +++ /dev/null @@ -1,3237 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: MimeLookups.cs -* -* MimeLookups.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace VNLib.Net.Http -{ - public static partial class HttpHelpers - { - //Content type lookup dict - private static readonly IReadOnlyDictionary<ContentType, string> CtToMime = new Dictionary<ContentType, string>() - { - { ContentType.NonSupported, "application/octet-stream" }, - { ContentType.UrlEncoded, "application/x-www-form-urlencoded" }, - { ContentType.MultiPart, "multipart/form-data" }, - { ContentType.Aab, "application/x-authorware-bin" }, - { ContentType.Aac, "audio/x-aac" }, - { ContentType.Aam, "application/x-authorware-map" }, - { ContentType.Aas, "application/x-authorware-seg" }, - { ContentType.Abw, "application/x-abiword" }, - { ContentType.Ac, "application/pkix-attr-cert" }, - { ContentType.Acc, "application/vnd.americandynamics.acc" }, - { ContentType.Ace, "application/x-ace-compressed" }, - { ContentType.Acu, "application/vnd.acucobol" }, - { ContentType.Acutc, "application/vnd.acucorp" }, - { ContentType.Adp, "audio/adpcm" }, - { ContentType.Aep, "application/vnd.audiograph" }, - { ContentType.Afm, "application/x-font-type1" }, - { ContentType.Afp, "application/vnd.ibm.modcap" }, - { ContentType.Ahead, "application/vnd.ahead.space" }, - { ContentType.Ai, "application/postscript" }, - { ContentType.Aif, "audio/x-aiff" }, - { ContentType.Aifc, "audio/x-aiff" }, - { ContentType.Aiff, "audio/x-aiff" }, - { ContentType.Air, "application/vnd.adobe.air-application-installer-package+zip" }, - { ContentType.Ait, "application/vnd.dvb.ait" }, - { ContentType.Ami, "application/vnd.amiga.ami" }, - { ContentType.Amr, "audio/amr" }, - { ContentType.Apk, "application/vnd.android.package-archive" }, - { ContentType.Apng, "image/apng" }, - { ContentType.Appcache, "text/cache-manifest" }, - { ContentType.Apr, "application/vnd.lotus-approach" }, - { ContentType.Arc, "application/x-freearc" }, - { ContentType.Arj, "application/x-arj" }, - { ContentType.Asc, "application/pgp-signature" }, - { ContentType.Asf, "video/x-ms-asf" }, - { ContentType.Asm, "text/x-asm" }, - { ContentType.Aso, "application/vnd.accpac.simply.aso" }, - { ContentType.Asx, "video/x-ms-asf" }, - { ContentType.Atc, "application/vnd.acucorp" }, - { ContentType.Atom, "application/atom+xml" }, - { ContentType.Atomcat, "application/atomcat+xml" }, - { ContentType.Atomsvc, "application/atomsvc+xml" }, - { ContentType.Atx, "application/vnd.antix.game-component" }, - { ContentType.Au, "audio/basic" }, - { ContentType.Avi, "video/x-msvideo" }, - { ContentType.Avif, "image/avif" }, - { ContentType.Aw, "application/applixware" }, - { ContentType.Azf, "application/vnd.airzip.filesecure.azf" }, - { ContentType.Azs, "application/vnd.airzip.filesecure.azs" }, - { ContentType.Azv, "image/vnd.airzip.accelerator.azv" }, - { ContentType.Azw, "application/vnd.amazon.ebook" }, - { ContentType.B16, "image/vnd.pco.b16" }, - { ContentType.Bat, "application/x-msdownload" }, - { ContentType.Bcpio, "application/x-bcpio" }, - { ContentType.Bdf, "application/x-font-bdf" }, - { ContentType.Bdm, "application/vnd.syncml.dm+wbxml" }, - { ContentType.Bdoc, "application/bdoc" }, - { ContentType.Bed, "application/vnd.realvnc.bed" }, - { ContentType.Bh2, "application/vnd.fujitsu.oasysprs" }, - { ContentType.Binary, "application/octet-stream" }, - { ContentType.Blb, "application/x-blorb" }, - { ContentType.Blorb, "application/x-blorb" }, - { ContentType.Bmi, "application/vnd.bmi" }, - { ContentType.Bmml, "application/vnd.balsamiq.bmml+xml" }, - { ContentType.Bmp, "image/bmp" }, - { ContentType.Book, "application/vnd.framemaker" }, - { ContentType.Box, "application/vnd.previewsystems.box" }, - { ContentType.Boz, "application/x-bzip2" }, - { ContentType.Bpk, "application/octet-stream" }, - { ContentType.Bsp, "model/vnd.valve.source.compiled-map" }, - { ContentType.Btif, "image/prs.btif" }, - { ContentType.Buffer, "application/octet-stream" }, - { ContentType.Bz, "application/x-bzip" }, - { ContentType.Bz2, "application/x-bzip2" }, - { ContentType.C, "text/x-c" }, - { ContentType.C11amc, "application/vnd.cluetrust.cartomobile-config" }, - { ContentType.C11amz, "application/vnd.cluetrust.cartomobile-config-pkg" }, - { ContentType.C4d, "application/vnd.clonk.c4group" }, - { ContentType.C4f, "application/vnd.clonk.c4group" }, - { ContentType.C4g, "application/vnd.clonk.c4group" }, - { ContentType.C4p, "application/vnd.clonk.c4group" }, - { ContentType.C4u, "application/vnd.clonk.c4group" }, - { ContentType.Cab, "application/vnd.ms-cab-compressed" }, - { ContentType.Caf, "audio/x-caf" }, - { ContentType.Cap, "application/vnd.tcpdump.pcap" }, - { ContentType.Car, "application/vnd.curl.car" }, - { ContentType.Cat, "application/vnd.ms-pki.seccat" }, - { ContentType.Cb7, "application/x-cbr" }, - { ContentType.Cba, "application/x-cbr" }, - { ContentType.Cbr, "application/x-cbr" }, - { ContentType.Cbt, "application/x-cbr" }, - { ContentType.Cbz, "application/x-cbr" }, - { ContentType.Cc, "text/x-c" }, - { ContentType.Cco, "application/x-cocoa" }, - { ContentType.Cct, "application/x-director" }, - { ContentType.Ccxml, "application/ccxml+xml" }, - { ContentType.Cdbcmsg, "application/vnd.contact.cmsg" }, - { ContentType.Cdf, "application/x-netcdf" }, - { ContentType.Cdfx, "application/cdfx+xml" }, - { ContentType.Cdkey, "application/vnd.mediastation.cdkey" }, - { ContentType.Cdmia, "application/cdmi-capability" }, - { ContentType.Cdmic, "application/cdmi-container" }, - { ContentType.Cdmid, "application/cdmi-domain" }, - { ContentType.Cdmio, "application/cdmi-object" }, - { ContentType.Cdmiq, "application/cdmi-queue" }, - { ContentType.Cdx, "chemical/x-cdx" }, - { ContentType.Cdxml, "application/vnd.chemdraw+xml" }, - { ContentType.Cdy, "application/vnd.cinderella" }, - { ContentType.Cer, "application/pkix-cert" }, - { ContentType.Cfs, "application/x-cfs-compressed" }, - { ContentType.Cgm, "image/cgm" }, - { ContentType.Chat, "application/x-chat" }, - { ContentType.Chm, "application/vnd.ms-htmlhelp" }, - { ContentType.Chrt, "application/vnd.kde.kchart" }, - { ContentType.Cif, "chemical/x-cif" }, - { ContentType.Cii, "application/vnd.anser-web-certificate-issue-initiation" }, - { ContentType.Cil, "application/vnd.ms-artgalry" }, - { ContentType.Cjs, "application/node" }, - { ContentType.Cla, "application/vnd.claymore" }, - { ContentType.Clkk, "application/vnd.crick.clicker.keyboard" }, - { ContentType.Clkp, "application/vnd.crick.clicker.palette" }, - { ContentType.Clkt, "application/vnd.crick.clicker.template" }, - { ContentType.Clkw, "application/vnd.crick.clicker.wordbank" }, - { ContentType.Clkx, "application/vnd.crick.clicker" }, - { ContentType.Clp, "application/x-msclip" }, - { ContentType.Cmc, "application/vnd.cosmocaller" }, - { ContentType.Cmdf, "chemical/x-cmdf" }, - { ContentType.Cml, "chemical/x-cml" }, - { ContentType.Cmp, "application/vnd.yellowriver-custom-menu" }, - { ContentType.Cmx, "image/x-cmx" }, - { ContentType.Cod, "application/vnd.rim.cod" }, - { ContentType.Coffee, "text/coffeescript" }, - { ContentType.Com, "application/x-msdownload" }, - { ContentType.Conf, "text/plain" }, - { ContentType.Cpio, "application/x-cpio" }, - { ContentType.Cpp, "text/x-c" }, - { ContentType.Cpt, "application/mac-compactpro" }, - { ContentType.Crd, "application/x-mscardfile" }, - { ContentType.Crl, "application/pkix-crl" }, - { ContentType.Crt, "application/x-x509-ca-cert" }, - { ContentType.Crx, "application/x-chrome-extension" }, - { ContentType.Csh, "application/x-csh" }, - { ContentType.Csl, "application/vnd.citationstyles.style+xml" }, - { ContentType.Csml, "chemical/x-csml" }, - { ContentType.Csp, "application/vnd.commonspace" }, - { ContentType.Css, "text/css" }, - { ContentType.Cst, "application/x-director" }, - { ContentType.Csv, "text/csv" }, - { ContentType.Cu, "application/cu-seeme" }, - { ContentType.Curl, "text/vnd.curl" }, - { ContentType.Cww, "application/prs.cww" }, - { ContentType.Cxt, "application/x-director" }, - { ContentType.Cxx, "text/x-c" }, - { ContentType.Dae, "model/vnd.collada+xml" }, - { ContentType.Daf, "application/vnd.mobius.daf" }, - { ContentType.Dart, "application/vnd.dart" }, - { ContentType.Dataless, "application/vnd.fdsn.seed" }, - { ContentType.Davmount, "application/davmount+xml" }, - { ContentType.Dbf, "application/vnd.dbf" }, - { ContentType.Dbk, "application/docbook+xml" }, - { ContentType.Dcr, "application/x-director" }, - { ContentType.Dcurl, "text/vnd.curl.dcurl" }, - { ContentType.Dd2, "application/vnd.oma.dd2+xml" }, - { ContentType.Ddd, "application/vnd.fujixerox.ddd" }, - { ContentType.Ddf, "application/vnd.syncml.dmddf+xml" }, - { ContentType.Dds, "image/vnd.ms-dds" }, - { ContentType.Deb, "application/octet-stream" }, - { ContentType.Def, "text/plain" }, - { ContentType.Deploy, "application/octet-stream" }, - { ContentType.Der, "application/x-x509-ca-cert" }, - { ContentType.Dfac, "application/vnd.dreamfactory" }, - { ContentType.Dgc, "application/x-dgc-compressed" }, - { ContentType.Dic, "text/x-c" }, - { ContentType.Dir, "application/x-director" }, - { ContentType.Dis, "application/vnd.mobius.dis" }, - { ContentType.Dist, "application/octet-stream" }, - { ContentType.Distz, "application/octet-stream" }, - { ContentType.Djv, "image/vnd.djvu" }, - { ContentType.Djvu, "image/vnd.djvu" }, - { ContentType.Dll, "application/octet-stream" }, - { ContentType.Dmg, "application/octet-stream" }, - { ContentType.Dmp, "application/vnd.tcpdump.pcap" }, - { ContentType.Dms, "application/octet-stream" }, - { ContentType.Dna, "application/vnd.dna" }, - { ContentType.Doc, "application/msword" }, - { ContentType.Docm, "application/vnd.ms-word.document.macroenabled.12" }, - { ContentType.Docx, "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, - { ContentType.Dot, "application/msword" }, - { ContentType.Dotm, "application/vnd.ms-word.template.macroenabled.12" }, - { ContentType.Dotx, "application/vnd.openxmlformats-officedocument.wordprocessingml.template" }, - { ContentType.Dp, "application/vnd.osgi.dp" }, - { ContentType.Dpg, "application/vnd.dpgraph" }, - { ContentType.Dra, "audio/vnd.dra" }, - { ContentType.Drle, "image/dicom-rle" }, - { ContentType.Dsc, "text/prs.lines.tag" }, - { ContentType.Dssc, "application/dssc+der" }, - { ContentType.Dtb, "application/x-dtbook+xml" }, - { ContentType.Dtd, "application/xml-dtd" }, - { ContentType.Dts, "audio/vnd.dts" }, - { ContentType.Dtshd, "audio/vnd.dts.hd" }, - { ContentType.Dump, "application/octet-stream" }, - { ContentType.Dvb, "video/vnd.dvb.file" }, - { ContentType.Dvi, "application/x-dvi" }, - { ContentType.Dwd, "application/atsc-dwd+xml" }, - { ContentType.Dwf, "model/vnd.dwf" }, - { ContentType.Dwg, "image/vnd.dwg" }, - { ContentType.Dxf, "image/vnd.dxf" }, - { ContentType.Dxp, "application/vnd.spotfire.dxp" }, - { ContentType.Dxr, "application/x-director" }, - { ContentType.Ear, "application/java-archive" }, - { ContentType.Ecma, "application/ecmascript" }, - { ContentType.Edm, "application/vnd.novadigm.edm" }, - { ContentType.Edx, "application/vnd.novadigm.edx" }, - { ContentType.Efif, "application/vnd.picsel" }, - { ContentType.Ei6, "application/vnd.pg.osasli" }, - { ContentType.Elc, "application/octet-stream" }, - { ContentType.Emf, "application/x-msmetafile" }, - { ContentType.Eml, "message/rfc822" }, - { ContentType.Emma, "application/emma+xml" }, - { ContentType.Emz, "application/x-msmetafile" }, - { ContentType.Eol, "audio/vnd.digital-winds" }, - { ContentType.Eot, "application/vnd.ms-fontobject" }, - { ContentType.Eps, "application/postscript" }, - { ContentType.Epub, "application/epub+zip" }, - { ContentType.Es, "application/ecmascript" }, - { ContentType.Es3, "application/vnd.eszigno3+xml" }, - { ContentType.Esa, "application/vnd.osgi.subsystem" }, - { ContentType.Esf, "application/vnd.epson.esf" }, - { ContentType.Et3, "application/vnd.eszigno3+xml" }, - { ContentType.Etx, "text/x-setext" }, - { ContentType.Eva, "application/x-eva" }, - { ContentType.Evy, "application/x-envoy" }, - { ContentType.Exe, "application/octet-stream" }, - { ContentType.Exi, "application/exi" }, - { ContentType.Exp, "application/express" }, - { ContentType.Exr, "image/aces" }, - { ContentType.Ext, "application/vnd.novadigm.ext" }, - { ContentType.Ez, "application/andrew-inset" }, - { ContentType.Ez2, "application/vnd.ezpix-album" }, - { ContentType.Ez3, "application/vnd.ezpix-package" }, - { ContentType.F, "text/x-fortran" }, - { ContentType.F4v, "video/x-f4v" }, - { ContentType.Fortran, "text/x-fortran" }, - { ContentType.F90, "text/x-fortran" }, - { ContentType.Fbs, "image/vnd.fastbidsheet" }, - { ContentType.Fcdt, "application/vnd.adobe.formscentral.fcdt" }, - { ContentType.Fcs, "application/vnd.isac.fcs" }, - { ContentType.Fdf, "application/vnd.fdf" }, - { ContentType.Fdt, "application/fdt+xml" }, - { ContentType.Fg5, "application/vnd.fujitsu.oasysgp" }, - { ContentType.Fgd, "application/x-director" }, - { ContentType.Fh, "image/x-freehand" }, - { ContentType.Fh4, "image/x-freehand" }, - { ContentType.Fh5, "image/x-freehand" }, - { ContentType.Fh7, "image/x-freehand" }, - { ContentType.Fhc, "image/x-freehand" }, - { ContentType.Fig, "application/x-xfig" }, - { ContentType.Fits, "image/fits" }, - { ContentType.Flac, "audio/x-flac" }, - { ContentType.Fli, "video/x-fli" }, - { ContentType.Flo, "application/vnd.micrografx.flo" }, - { ContentType.Flv, "video/x-flv" }, - { ContentType.Flw, "application/vnd.kde.kivio" }, - { ContentType.Flx, "text/vnd.fmi.flexstor" }, - { ContentType.Fly, "text/vnd.fly" }, - { ContentType.Fm, "application/vnd.framemaker" }, - { ContentType.Fnc, "application/vnd.frogans.fnc" }, - { ContentType.Fo, "application/vnd.software602.filler.form+xml" }, - { ContentType.For, "text/x-fortran" }, - { ContentType.Fpx, "image/vnd.fpx" }, - { ContentType.Frame, "application/vnd.framemaker" }, - { ContentType.Fsc, "application/vnd.fsc.weblaunch" }, - { ContentType.Fst, "image/vnd.fst" }, - { ContentType.Ftc, "application/vnd.fluxtime.clip" }, - { ContentType.Fti, "application/vnd.anser-web-funds-transfer-initiation" }, - { ContentType.Fvt, "video/vnd.fvt" }, - { ContentType.Fxp, "application/vnd.adobe.fxp" }, - { ContentType.Fxpl, "application/vnd.adobe.fxp" }, - { ContentType.Fzs, "application/vnd.fuzzysheet" }, - { ContentType.G2w, "application/vnd.geoplan" }, - { ContentType.G3, "image/g3fax" }, - { ContentType.G3w, "application/vnd.geospace" }, - { ContentType.Gac, "application/vnd.groove-account" }, - { ContentType.Gam, "application/x-tads" }, - { ContentType.Gbr, "application/rpki-ghostbusters" }, - { ContentType.Gca, "application/x-gca-compressed" }, - { ContentType.Gdl, "model/vnd.gdl" }, - { ContentType.Gdoc, "application/vnd.google-apps.document" }, - { ContentType.Geo, "application/vnd.dynageo" }, - { ContentType.Geojson, "application/geo+json" }, - { ContentType.Gex, "application/vnd.geometry-explorer" }, - { ContentType.Ggb, "application/vnd.geogebra.file" }, - { ContentType.Ggt, "application/vnd.geogebra.tool" }, - { ContentType.Ghf, "application/vnd.groove-help" }, - { ContentType.Gif, "image/gif" }, - { ContentType.Gim, "application/vnd.groove-identity-message" }, - { ContentType.Glb, "model/gltf-binary" }, - { ContentType.Gltf, "model/gltf+json" }, - { ContentType.Gml, "application/gml+xml" }, - { ContentType.Gmx, "application/vnd.gmx" }, - { ContentType.Gnumeric, "application/x-gnumeric" }, - { ContentType.Gph, "application/vnd.flographit" }, - { ContentType.Gpx, "application/gpx+xml" }, - { ContentType.Gqf, "application/vnd.grafeq" }, - { ContentType.Gqs, "application/vnd.grafeq" }, - { ContentType.Gram, "application/srgs" }, - { ContentType.Gramps, "application/x-gramps-xml" }, - { ContentType.Gre, "application/vnd.geometry-explorer" }, - { ContentType.Grv, "application/vnd.groove-injector" }, - { ContentType.Grxml, "application/srgs+xml" }, - { ContentType.Gsf, "application/x-font-ghostscript" }, - { ContentType.Gsheet, "application/vnd.google-apps.spreadsheet" }, - { ContentType.Gslides, "application/vnd.google-apps.presentation" }, - { ContentType.Gtar, "application/x-gtar" }, - { ContentType.Gtm, "application/vnd.groove-tool-message" }, - { ContentType.Gtw, "model/vnd.gtw" }, - { ContentType.Gv, "text/vnd.graphviz" }, - { ContentType.Gxf, "application/gxf" }, - { ContentType.Gxt, "application/vnd.geonext" }, - { ContentType.Gz, "application/gzip" }, - { ContentType.H, "text/x-c" }, - { ContentType.H261, "video/h261" }, - { ContentType.H263, "video/h263" }, - { ContentType.H264, "video/h264" }, - { ContentType.Hal, "application/vnd.hal+xml" }, - { ContentType.Hbci, "application/vnd.hbci" }, - { ContentType.Hbs, "text/x-handlebars-template" }, - { ContentType.Hdd, "application/x-virtualbox-hdd" }, - { ContentType.Hdf, "application/x-hdf" }, - { ContentType.Heic, "image/heic" }, - { ContentType.Heics, "image/heic-sequence" }, - { ContentType.Heif, "image/heif" }, - { ContentType.Heifs, "image/heif-sequence" }, - { ContentType.Hej2, "image/hej2k" }, - { ContentType.Held, "application/atsc-held+xml" }, - { ContentType.Hh, "text/x-c" }, - { ContentType.Hjson, "application/hjson" }, - { ContentType.Hlp, "application/winhlp" }, - { ContentType.Hpgl, "application/vnd.hp-hpgl" }, - { ContentType.Hpid, "application/vnd.hp-hpid" }, - { ContentType.Hps, "application/vnd.hp-hps" }, - { ContentType.Hqx, "application/mac-binhex40" }, - { ContentType.Hsj2, "image/hsj2" }, - { ContentType.Htc, "text/x-component" }, - { ContentType.Htke, "application/vnd.kenameaapp" }, - { ContentType.Htm, "text/html" }, - { ContentType.Html, "text/html" }, - { ContentType.Hvd, "application/vnd.yamaha.hv-dic" }, - { ContentType.Hvp, "application/vnd.yamaha.hv-voice" }, - { ContentType.Hvs, "application/vnd.yamaha.hv-script" }, - { ContentType.I2g, "application/vnd.intergeo" }, - { ContentType.Icc, "application/vnd.iccprofile" }, - { ContentType.Ice, "x-conference/x-cooltalk" }, - { ContentType.Icm, "application/vnd.iccprofile" }, - { ContentType.Ico, "image/vnd.microsoft.icon" }, - { ContentType.Ics, "text/calendar" }, - { ContentType.Ief, "image/ief" }, - { ContentType.Ifb, "text/calendar" }, - { ContentType.Ifm, "application/vnd.shana.informed.formdata" }, - { ContentType.Iges, "model/iges" }, - { ContentType.Igl, "application/vnd.igloader" }, - { ContentType.Igm, "application/vnd.insors.igm" }, - { ContentType.Igs, "model/iges" }, - { ContentType.Igx, "application/vnd.micrografx.igx" }, - { ContentType.Iif, "application/vnd.shana.informed.interchange" }, - { ContentType.Img, "application/octet-stream" }, - { ContentType.Imp, "application/vnd.accpac.simply.imp" }, - { ContentType.Ims, "application/vnd.ms-ims" }, - { ContentType.Ini, "text/plain" }, - { ContentType.Ink, "application/inkml+xml" }, - { ContentType.Inkml, "application/inkml+xml" }, - { ContentType.Install, "application/x-install-instructions" }, - { ContentType.Iota, "application/vnd.astraea-software.iota" }, - { ContentType.Ipfix, "application/ipfix" }, - { ContentType.Ipk, "application/vnd.shana.informed.package" }, - { ContentType.Irm, "application/vnd.ibm.rights-management" }, - { ContentType.Irp, "application/vnd.irepository.package+xml" }, - { ContentType.Iso, "application/octet-stream" }, - { ContentType.Itp, "application/vnd.shana.informed.formtemplate" }, - { ContentType.Its, "application/its+xml" }, - { ContentType.Ivp, "application/vnd.immervision-ivp" }, - { ContentType.Ivu, "application/vnd.immervision-ivu" }, - { ContentType.Jad, "text/vnd.sun.j2me.app-descriptor" }, - { ContentType.Jade, "text/jade" }, - { ContentType.Jam, "application/vnd.jam" }, - { ContentType.Jar, "application/java-archive" }, - { ContentType.Jardiff, "application/x-java-archive-diff" }, - { ContentType.Java, "text/x-java-source" }, - { ContentType.Jhc, "image/jphc" }, - { ContentType.Jisp, "application/vnd.jisp" }, - { ContentType.Jls, "image/jls" }, - { ContentType.Jlt, "application/vnd.hp-jlyt" }, - { ContentType.Jng, "image/x-jng" }, - { ContentType.Jnlp, "application/x-java-jnlp-file" }, - { ContentType.Joda, "application/vnd.joost.joda-archive" }, - { ContentType.Jp2, "image/jp2" }, - { ContentType.Jpe, "image/jpeg" }, - { ContentType.Jpeg, "image/jpeg" }, - { ContentType.Jpf, "image/jpx" }, - { ContentType.Jpg, "image/jpeg" }, - { ContentType.Jpg2, "image/jp2" }, - { ContentType.Jpgm, "video/jpm" }, - { ContentType.Jpgv, "video/jpeg" }, - { ContentType.Jph, "image/jph" }, - { ContentType.Jpm, "image/jpm" }, - { ContentType.Jpx, "image/jpx" }, - { ContentType.Javascript, "application/javascript" }, - { ContentType.Json, "application/json" }, - { ContentType.Json5, "application/json5" }, - { ContentType.Jsonld, "application/ld+json" }, - { ContentType.Jsonml, "application/jsonml+json" }, - { ContentType.Jsx, "text/jsx" }, - { ContentType.Jxr, "image/jxr" }, - { ContentType.Jxra, "image/jxra" }, - { ContentType.Jxrs, "image/jxrs" }, - { ContentType.Jxs, "image/jxs" }, - { ContentType.Jxsc, "image/jxsc" }, - { ContentType.Jxsi, "image/jxsi" }, - { ContentType.Jxss, "image/jxss" }, - { ContentType.Kar, "audio/midi" }, - { ContentType.Karbon, "application/vnd.kde.karbon" }, - { ContentType.Kdbx, "application/x-keepass2" }, - { ContentType.Key, "application/vnd.apple.keynote" }, - { ContentType.Kfo, "application/vnd.kde.kformula" }, - { ContentType.Kia, "application/vnd.kidspiration" }, - { ContentType.Kml, "application/vnd.google-earth.kml+xml" }, - { ContentType.Kmz, "application/vnd.google-earth.kmz" }, - { ContentType.Kne, "application/vnd.kinar" }, - { ContentType.Knp, "application/vnd.kinar" }, - { ContentType.Kon, "application/vnd.kde.kontour" }, - { ContentType.Kpr, "application/vnd.kde.kpresenter" }, - { ContentType.Kpt, "application/vnd.kde.kpresenter" }, - { ContentType.Kpxx, "application/vnd.ds-keypoint" }, - { ContentType.Ksp, "application/vnd.kde.kspread" }, - { ContentType.Ktr, "application/vnd.kahootz" }, - { ContentType.Ktx, "image/ktx" }, - { ContentType.Ktx2, "image/ktx2" }, - { ContentType.Ktz, "application/vnd.kahootz" }, - { ContentType.Kwd, "application/vnd.kde.kword" }, - { ContentType.Kwt, "application/vnd.kde.kword" }, - { ContentType.Lasxml, "application/vnd.las.las+xml" }, - { ContentType.Latex, "application/x-latex" }, - { ContentType.Lbd, "application/vnd.llamagraphics.life-balance.desktop" }, - { ContentType.Lbe, "application/vnd.llamagraphics.life-balance.exchange+xml" }, - { ContentType.Les, "application/vnd.hhe.lesson-player" }, - { ContentType.Less, "text/less" }, - { ContentType.Lgr, "application/lgr+xml" }, - { ContentType.Lha, "application/x-lzh-compressed" }, - { ContentType.Link66, "application/vnd.route66.link66+xml" }, - { ContentType.List, "text/plain" }, - { ContentType.List3820, "application/vnd.ibm.modcap" }, - { ContentType.Listafp, "application/vnd.ibm.modcap" }, - { ContentType.Lnk, "application/x-ms-shortcut" }, - { ContentType.Log, "text/plain" }, - { ContentType.Lostxml, "application/lost+xml" }, - { ContentType.Lrf, "application/octet-stream" }, - { ContentType.Lrm, "application/vnd.ms-lrm" }, - { ContentType.Ltf, "application/vnd.frogans.ltf" }, - { ContentType.Lua, "text/x-lua" }, - { ContentType.Luac, "application/x-lua-bytecode" }, - { ContentType.Lvp, "audio/vnd.lucent.voice" }, - { ContentType.Lwp, "application/vnd.lotus-wordpro" }, - { ContentType.Lzh, "application/x-lzh-compressed" }, - { ContentType.M13, "application/x-msmediaview" }, - { ContentType.M14, "application/x-msmediaview" }, - { ContentType.M1v, "video/mpeg" }, - { ContentType.M21, "application/mp21" }, - { ContentType.M2a, "audio/mpeg" }, - { ContentType.M2v, "video/mpeg" }, - { ContentType.M3a, "audio/mpeg" }, - { ContentType.M3u, "audio/x-mpegurl" }, - { ContentType.M3u8, "application/vnd.apple.mpegurl" }, - { ContentType.M4a, "audio/mp4" }, - { ContentType.M4p, "application/mp4" }, - { ContentType.M4s, "video/iso.segment" }, - { ContentType.M4u, "video/vnd.mpegurl" }, - { ContentType.M4v, "video/x-m4v" }, - { ContentType.Ma, "application/mathematica" }, - { ContentType.Mads, "application/mads+xml" }, - { ContentType.Maei, "application/mmt-aei+xml" }, - { ContentType.Mag, "application/vnd.ecowin.chart" }, - { ContentType.Maker, "application/vnd.framemaker" }, - { ContentType.Man, "text/troff" }, - { ContentType.Manifest, "text/cache-manifest" }, - { ContentType.Map, "application/json" }, - { ContentType.Mar, "application/octet-stream" }, - { ContentType.Markdown, "text/markdown" }, - { ContentType.Mathml, "application/mathml+xml" }, - { ContentType.Mb, "application/mathematica" }, - { ContentType.Mbk, "application/vnd.mobius.mbk" }, - { ContentType.Mbox, "application/mbox" }, - { ContentType.Mc1, "application/vnd.medcalcdata" }, - { ContentType.Mcd, "application/vnd.mcd" }, - { ContentType.Mcurl, "text/vnd.curl.mcurl" }, - { ContentType.Md, "text/markdown" }, - { ContentType.Mdb, "application/x-msaccess" }, - { ContentType.Mdi, "image/vnd.ms-modi" }, - { ContentType.Mdx, "text/mdx" }, - { ContentType.Me, "text/troff" }, - { ContentType.Mesh, "model/mesh" }, - { ContentType.Meta4, "application/metalink4+xml" }, - { ContentType.Metalink, "application/metalink+xml" }, - { ContentType.Mets, "application/mets+xml" }, - { ContentType.Mfm, "application/vnd.mfmp" }, - { ContentType.Mft, "application/rpki-manifest" }, - { ContentType.Mgp, "application/vnd.osgeo.mapguide.package" }, - { ContentType.Mgz, "application/vnd.proteus.magazine" }, - { ContentType.Mid, "audio/midi" }, - { ContentType.Midi, "audio/midi" }, - { ContentType.Mie, "application/x-mie" }, - { ContentType.Mif, "application/vnd.mif" }, - { ContentType.Mime, "message/rfc822" }, - { ContentType.Mj2, "video/mj2" }, - { ContentType.Mjp2, "video/mj2" }, - { ContentType.Mjs, "application/javascript" }, - { ContentType.Mk3d, "video/x-matroska" }, - { ContentType.Mka, "audio/x-matroska" }, - { ContentType.Mkd, "text/x-markdown" }, - { ContentType.Mks, "video/x-matroska" }, - { ContentType.Mkv, "video/x-matroska" }, - { ContentType.Mlp, "application/vnd.dolby.mlp" }, - { ContentType.Mmd, "application/vnd.chipnuts.karaoke-mmd" }, - { ContentType.Mmf, "application/vnd.smaf" }, - { ContentType.Mml, "text/mathml" }, - { ContentType.Mmr, "image/vnd.fujixerox.edmics-mmr" }, - { ContentType.Mng, "video/x-mng" }, - { ContentType.Mny, "application/x-msmoney" }, - { ContentType.Mobi, "application/x-mobipocket-ebook" }, - { ContentType.Mods, "application/mods+xml" }, - { ContentType.Mov, "video/quicktime" }, - { ContentType.Movie, "video/x-sgi-movie" }, - { ContentType.Mp2, "audio/mpeg" }, - { ContentType.Mp21, "application/mp21" }, - { ContentType.Mp2a, "audio/mpeg" }, - { ContentType.Mp3, "audio/mp3" }, - { ContentType.Mp4, "video/mp4" }, - { ContentType.Mp4a, "audio/mp4" }, - { ContentType.Mp4s, "application/mp4" }, - { ContentType.Mp4v, "video/mp4" }, - { ContentType.Mpc, "application/vnd.mophun.certificate" }, - { ContentType.Mpd, "application/dash+xml" }, - { ContentType.Mpe, "video/mpeg" }, - { ContentType.Mpeg, "video/mpeg" }, - { ContentType.Mpg, "video/mpeg" }, - { ContentType.Mpg4, "video/mp4" }, - { ContentType.Mpga, "audio/mpeg" }, - { ContentType.Mpkg, "application/vnd.apple.installer+xml" }, - { ContentType.Mpm, "application/vnd.blueice.multipass" }, - { ContentType.Mpn, "application/vnd.mophun.application" }, - { ContentType.Mpp, "application/vnd.ms-project" }, - { ContentType.Mpt, "application/vnd.ms-project" }, - { ContentType.Mpy, "application/vnd.ibm.minipay" }, - { ContentType.Mqy, "application/vnd.mobius.mqy" }, - { ContentType.Mrc, "application/marc" }, - { ContentType.Mrcx, "application/marcxml+xml" }, - { ContentType.Ms, "text/troff" }, - { ContentType.Mscml, "application/mediaservercontrol+xml" }, - { ContentType.Mseed, "application/vnd.fdsn.mseed" }, - { ContentType.Mseq, "application/vnd.mseq" }, - { ContentType.Msf, "application/vnd.epson.msf" }, - { ContentType.Msg, "application/vnd.ms-outlook" }, - { ContentType.Msh, "model/mesh" }, - { ContentType.Msi, "application/octet-stream" }, - { ContentType.Msl, "application/vnd.mobius.msl" }, - { ContentType.Msm, "application/octet-stream" }, - { ContentType.Msp, "application/octet-stream" }, - { ContentType.Msty, "application/vnd.muvee.style" }, - { ContentType.Mtl, "model/mtl" }, - { ContentType.Mts, "model/vnd.mts" }, - { ContentType.Mus, "application/vnd.musician" }, - { ContentType.Musd, "application/mmt-usd+xml" }, - { ContentType.Musicxml, "application/vnd.recordare.musicxml+xml" }, - { ContentType.Mvb, "application/x-msmediaview" }, - { ContentType.Mvt, "application/vnd.mapbox-vector-tile" }, - { ContentType.Mwf, "application/vnd.mfer" }, - { ContentType.Mxf, "application/mxf" }, - { ContentType.Mxl, "application/vnd.recordare.musicxml" }, - { ContentType.Mxmf, "audio/mobile-xmf" }, - { ContentType.Mxml, "application/xv+xml" }, - { ContentType.Mxs, "application/vnd.triscape.mxs" }, - { ContentType.Mxu, "video/vnd.mpegurl" }, - { ContentType.N3, "text/n3" }, - { ContentType.Nb, "application/mathematica" }, - { ContentType.Nbp, "application/vnd.wolfram.player" }, - { ContentType.Nc, "application/x-netcdf" }, - { ContentType.Ncx, "application/x-dtbncx+xml" }, - { ContentType.Nfo, "text/x-nfo" }, - { ContentType.Ngdat, "application/vnd.nokia.n-gage.data" }, - { ContentType.Nitf, "application/vnd.nitf" }, - { ContentType.Nlu, "application/vnd.neurolanguage.nlu" }, - { ContentType.Nml, "application/vnd.enliven" }, - { ContentType.Nnd, "application/vnd.noblenet-directory" }, - { ContentType.Nns, "application/vnd.noblenet-sealer" }, - { ContentType.Nnw, "application/vnd.noblenet-web" }, - { ContentType.Npx, "image/vnd.net-fpx" }, - { ContentType.Nq, "application/n-quads" }, - { ContentType.Nsc, "application/x-conference" }, - { ContentType.Nsf, "application/vnd.lotus-notes" }, - { ContentType.Nt, "application/n-triples" }, - { ContentType.Ntf, "application/vnd.nitf" }, - { ContentType.Numbers, "application/vnd.apple.numbers" }, - { ContentType.Nzb, "application/x-nzb" }, - { ContentType.Oa2, "application/vnd.fujitsu.oasys2" }, - { ContentType.Oa3, "application/vnd.fujitsu.oasys3" }, - { ContentType.Oas, "application/vnd.fujitsu.oasys" }, - { ContentType.Obd, "application/x-msbinder" }, - { ContentType.Obgx, "application/vnd.openblox.game+xml" }, - { ContentType.Obj, "application/x-tgif" }, - { ContentType.Oda, "application/oda" }, - { ContentType.Odb, "application/vnd.oasis.opendocument.database" }, - { ContentType.Odc, "application/vnd.oasis.opendocument.chart" }, - { ContentType.Odf, "application/vnd.oasis.opendocument.formula" }, - { ContentType.Odft, "application/vnd.oasis.opendocument.formula-template" }, - { ContentType.Odg, "application/vnd.oasis.opendocument.graphics" }, - { ContentType.Odi, "application/vnd.oasis.opendocument.image" }, - { ContentType.Odm, "application/vnd.oasis.opendocument.text-master" }, - { ContentType.Odp, "application/vnd.oasis.opendocument.presentation" }, - { ContentType.Ods, "application/vnd.oasis.opendocument.spreadsheet" }, - { ContentType.Odt, "application/vnd.oasis.opendocument.text" }, - { ContentType.Oga, "audio/ogg" }, - { ContentType.Ogex, "model/vnd.opengex" }, - { ContentType.Ogg, "audio/ogg" }, - { ContentType.Ogv, "video/ogg" }, - { ContentType.Ogx, "application/ogg" }, - { ContentType.Omdoc, "application/omdoc+xml" }, - { ContentType.Onepkg, "application/onenote" }, - { ContentType.Onetmp, "application/onenote" }, - { ContentType.Onetoc, "application/onenote" }, - { ContentType.Onetoc2, "application/onenote" }, - { ContentType.Opf, "application/oebps-package+xml" }, - { ContentType.Opml, "text/x-opml" }, - { ContentType.Oprc, "application/vnd.palm" }, - { ContentType.Opus, "audio/ogg" }, - { ContentType.Org, "application/vnd.lotus-organizer" }, - { ContentType.Osf, "application/vnd.yamaha.openscoreformat" }, - { ContentType.Osfpvg, "application/vnd.yamaha.openscoreformat.osfpvg+xml" }, - { ContentType.Osm, "application/vnd.openstreetmap.data+xml" }, - { ContentType.Otc, "application/vnd.oasis.opendocument.chart-template" }, - { ContentType.Otf, "font/otf" }, - { ContentType.Otg, "application/vnd.oasis.opendocument.graphics-template" }, - { ContentType.Oth, "application/vnd.oasis.opendocument.text-web" }, - { ContentType.Oti, "application/vnd.oasis.opendocument.image-template" }, - { ContentType.Otp, "application/vnd.oasis.opendocument.presentation-template" }, - { ContentType.Ots, "application/vnd.oasis.opendocument.spreadsheet-template" }, - { ContentType.Ott, "application/vnd.oasis.opendocument.text-template" }, - { ContentType.Ova, "application/x-virtualbox-ova" }, - { ContentType.Ovf, "application/x-virtualbox-ovf" }, - { ContentType.Owl, "application/rdf+xml" }, - { ContentType.Oxps, "application/oxps" }, - { ContentType.Oxt, "application/vnd.openofficeorg.extension" }, - { ContentType.P, "text/x-pascal" }, - { ContentType.P10, "application/pkcs10" }, - { ContentType.P12, "application/x-pkcs12" }, - { ContentType.P7b, "application/x-pkcs7-certificates" }, - { ContentType.P7c, "application/pkcs7-mime" }, - { ContentType.P7m, "application/pkcs7-mime" }, - { ContentType.P7r, "application/x-pkcs7-certreqresp" }, - { ContentType.P7s, "application/pkcs7-signature" }, - { ContentType.P8, "application/pkcs8" }, - { ContentType.Pac, "application/x-ns-proxy-autoconfig" }, - { ContentType.Pages, "application/vnd.apple.pages" }, - { ContentType.Pas, "text/x-pascal" }, - { ContentType.Paw, "application/vnd.pawaafile" }, - { ContentType.Pbd, "application/vnd.powerbuilder6" }, - { ContentType.Pbm, "image/x-portable-bitmap" }, - { ContentType.Pcap, "application/vnd.tcpdump.pcap" }, - { ContentType.Pcf, "application/x-font-pcf" }, - { ContentType.Pcl, "application/vnd.hp-pcl" }, - { ContentType.Pclxl, "application/vnd.hp-pclxl" }, - { ContentType.Pct, "image/x-pict" }, - { ContentType.Pcurl, "application/vnd.curl.pcurl" }, - { ContentType.Pcx, "image/vnd.zbrush.pcx" }, - { ContentType.Pdb, "application/vnd.palm" }, - { ContentType.Pde, "text/x-processing" }, - { ContentType.Pdf, "application/pdf" }, - { ContentType.Pem, "application/x-x509-ca-cert" }, - { ContentType.Pfa, "application/x-font-type1" }, - { ContentType.Pfb, "application/x-font-type1" }, - { ContentType.Pfm, "application/x-font-type1" }, - { ContentType.Pfr, "application/font-tdpfr" }, - { ContentType.Pfx, "application/x-pkcs12" }, - { ContentType.Pgm, "image/x-portable-graymap" }, - { ContentType.Pgn, "application/x-chess-pgn" }, - { ContentType.Pgp, "application/pgp-encrypted" }, - { ContentType.Php, "application/x-httpd-php" }, - { ContentType.Pic, "image/x-pict" }, - { ContentType.Pkg, "application/octet-stream" }, - { ContentType.Pki, "application/pkixcmp" }, - { ContentType.Pkipath, "application/pkix-pkipath" }, - { ContentType.Pkpass, "application/vnd.apple.pkpass" }, - { ContentType.Pl, "application/x-perl" }, - { ContentType.Plb, "application/vnd.3gpp.pic-bw-large" }, - { ContentType.Plc, "application/vnd.mobius.plc" }, - { ContentType.Plf, "application/vnd.pocketlearn" }, - { ContentType.Pls, "application/pls+xml" }, - { ContentType.Pm, "application/x-perl" }, - { ContentType.Pml, "application/vnd.ctc-posml" }, - { ContentType.Png, "image/png" }, - { ContentType.Pnm, "image/x-portable-anymap" }, - { ContentType.Portpkg, "application/vnd.macports.portpkg" }, - { ContentType.Pot, "application/vnd.ms-powerpoint" }, - { ContentType.Potm, "application/vnd.ms-powerpoint.template.macroenabled.12" }, - { ContentType.Potx, "application/vnd.openxmlformats-officedocument.presentationml.template" }, - { ContentType.Ppam, "application/vnd.ms-powerpoint.addin.macroenabled.12" }, - { ContentType.Ppd, "application/vnd.cups-ppd" }, - { ContentType.Ppm, "image/x-portable-pixmap" }, - { ContentType.Pps, "application/vnd.ms-powerpoint" }, - { ContentType.Ppsm, "application/vnd.ms-powerpoint.slideshow.macroenabled.12" }, - { ContentType.Ppsx, "application/vnd.openxmlformats-officedocument.presentationml.slideshow" }, - { ContentType.Ppt, "application/vnd.ms-powerpoint" }, - { ContentType.Pptm, "application/vnd.ms-powerpoint.presentation.macroenabled.12" }, - { ContentType.Pptx, "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, - { ContentType.Pqa, "application/vnd.palm" }, - { ContentType.Prc, "application/x-mobipocket-ebook" }, - { ContentType.Pre, "application/vnd.lotus-freelance" }, - { ContentType.Prf, "application/pics-rules" }, - { ContentType.Provx, "application/provenance+xml" }, - { ContentType.Ps, "application/postscript" }, - { ContentType.Psb, "application/vnd.3gpp.pic-bw-small" }, - { ContentType.Psd, "image/vnd.adobe.photoshop" }, - { ContentType.Psf, "application/x-font-linux-psf" }, - { ContentType.Pskcxml, "application/pskc+xml" }, - { ContentType.Pti, "image/prs.pti" }, - { ContentType.Ptid, "application/vnd.pvi.ptid1" }, - { ContentType.Pub, "application/x-mspublisher" }, - { ContentType.Pvb, "application/vnd.3gpp.pic-bw-var" }, - { ContentType.Pwn, "application/vnd.3m.post-it-notes" }, - { ContentType.Pya, "audio/vnd.ms-playready.media.pya" }, - { ContentType.Pyv, "video/vnd.ms-playready.media.pyv" }, - { ContentType.Qam, "application/vnd.epson.quickanime" }, - { ContentType.Qbo, "application/vnd.intu.qbo" }, - { ContentType.Qfx, "application/vnd.intu.qfx" }, - { ContentType.Qps, "application/vnd.publishare-delta-tree" }, - { ContentType.Qt, "video/quicktime" }, - { ContentType.Qwd, "application/vnd.quark.quarkxpress" }, - { ContentType.Qwt, "application/vnd.quark.quarkxpress" }, - { ContentType.Qxb, "application/vnd.quark.quarkxpress" }, - { ContentType.Qxd, "application/vnd.quark.quarkxpress" }, - { ContentType.Qxl, "application/vnd.quark.quarkxpress" }, - { ContentType.Qxt, "application/vnd.quark.quarkxpress" }, - { ContentType.Ra, "audio/x-pn-realaudio" }, - { ContentType.Ram, "audio/x-pn-realaudio" }, - { ContentType.Raml, "application/raml+yaml" }, - { ContentType.Rapd, "application/route-apd+xml" }, - { ContentType.Rar, "application/vnd.rar" }, - { ContentType.Ras, "image/x-cmu-raster" }, - { ContentType.Rdf, "application/rdf+xml" }, - { ContentType.Rdz, "application/vnd.data-vision.rdz" }, - { ContentType.Relo, "application/p2p-overlay+xml" }, - { ContentType.Rep, "application/vnd.businessobjects" }, - { ContentType.Res, "application/x-dtbresource+xml" }, - { ContentType.Rgb, "image/x-rgb" }, - { ContentType.Rif, "application/reginfo+xml" }, - { ContentType.Rip, "audio/vnd.rip" }, - { ContentType.Ris, "application/x-research-info-systems" }, - { ContentType.Rl, "application/resource-lists+xml" }, - { ContentType.Rlc, "image/vnd.fujixerox.edmics-rlc" }, - { ContentType.Rld, "application/resource-lists-diff+xml" }, - { ContentType.Rm, "application/vnd.rn-realmedia" }, - { ContentType.Rmi, "audio/midi" }, - { ContentType.Rmp, "audio/x-pn-realaudio-plugin" }, - { ContentType.Rms, "application/vnd.jcp.javame.midlet-rms" }, - { ContentType.Rmvb, "application/vnd.rn-realmedia-vbr" }, - { ContentType.Rnc, "application/relax-ng-compact-syntax" }, - { ContentType.Rng, "application/xml" }, - { ContentType.Roa, "application/rpki-roa" }, - { ContentType.Roff, "text/troff" }, - { ContentType.Rp9, "application/vnd.cloanto.rp9" }, - { ContentType.Rpm, "application/x-redhat-package-manager" }, - { ContentType.Rpss, "application/vnd.nokia.radio-presets" }, - { ContentType.Rpst, "application/vnd.nokia.radio-preset" }, - { ContentType.Rq, "application/sparql-query" }, - { ContentType.Rs, "application/rls-services+xml" }, - { ContentType.Rsat, "application/atsc-rsat+xml" }, - { ContentType.Rsd, "application/rsd+xml" }, - { ContentType.Rsheet, "application/urc-ressheet+xml" }, - { ContentType.Rss, "application/rss+xml" }, - { ContentType.Rtf, "application/rtf" }, - { ContentType.Rtx, "text/richtext" }, - { ContentType.Run, "application/x-makeself" }, - { ContentType.Rusd, "application/route-usd+xml" }, - { ContentType.S, "text/x-asm" }, - { ContentType.S3m, "audio/s3m" }, - { ContentType.Saf, "application/vnd.yamaha.smaf-audio" }, - { ContentType.Sass, "text/x-sass" }, - { ContentType.Sbml, "application/sbml+xml" }, - { ContentType.Sc, "application/vnd.ibm.secure-container" }, - { ContentType.Scd, "application/x-msschedule" }, - { ContentType.Scm, "application/vnd.lotus-screencam" }, - { ContentType.Scq, "application/scvp-cv-request" }, - { ContentType.Scs, "application/scvp-cv-response" }, - { ContentType.Scss, "text/x-scss" }, - { ContentType.Scurl, "text/vnd.curl.scurl" }, - { ContentType.Sda, "application/vnd.stardivision.draw" }, - { ContentType.Sdc, "application/vnd.stardivision.calc" }, - { ContentType.Sdd, "application/vnd.stardivision.impress" }, - { ContentType.Sdkd, "application/vnd.solent.sdkm+xml" }, - { ContentType.Sdkm, "application/vnd.solent.sdkm+xml" }, - { ContentType.Sdp, "application/sdp" }, - { ContentType.Sdw, "application/vnd.stardivision.writer" }, - { ContentType.Sea, "application/x-sea" }, - { ContentType.See, "application/vnd.seemail" }, - { ContentType.Seed, "application/vnd.fdsn.seed" }, - { ContentType.Sema, "application/vnd.sema" }, - { ContentType.Semd, "application/vnd.semd" }, - { ContentType.Semf, "application/vnd.semf" }, - { ContentType.Senmlx, "application/senml+xml" }, - { ContentType.Sensmlx, "application/sensml+xml" }, - { ContentType.Ser, "application/java-serialized-object" }, - { ContentType.Setpay, "application/set-payment-initiation" }, - { ContentType.Setreg, "application/set-registration-initiation" }, - { ContentType.Sfs, "application/vnd.spotfire.sfs" }, - { ContentType.Sfv, "text/x-sfv" }, - { ContentType.Sgi, "image/sgi" }, - { ContentType.Sgl, "application/vnd.stardivision.writer-global" }, - { ContentType.Sgm, "text/sgml" }, - { ContentType.Sgml, "text/sgml" }, - { ContentType.Sh, "application/x-sh" }, - { ContentType.Shar, "application/x-shar" }, - { ContentType.Shex, "text/shex" }, - { ContentType.Shf, "application/shf+xml" }, - { ContentType.Shtml, "text/html" }, - { ContentType.Sid, "image/x-mrsid-image" }, - { ContentType.Sieve, "application/sieve" }, - { ContentType.Sig, "application/pgp-signature" }, - { ContentType.Sil, "audio/silk" }, - { ContentType.Silo, "model/mesh" }, - { ContentType.Sis, "application/vnd.symbian.install" }, - { ContentType.Sisx, "application/vnd.symbian.install" }, - { ContentType.Sit, "application/x-stuffit" }, - { ContentType.Sitx, "application/x-stuffitx" }, - { ContentType.Siv, "application/sieve" }, - { ContentType.Skd, "application/vnd.koan" }, - { ContentType.Skm, "application/vnd.koan" }, - { ContentType.Skp, "application/vnd.koan" }, - { ContentType.Skt, "application/vnd.koan" }, - { ContentType.Sldm, "application/vnd.ms-powerpoint.slide.macroenabled.12" }, - { ContentType.Sldx, "application/vnd.openxmlformats-officedocument.presentationml.slide" }, - { ContentType.Slim, "text/slim" }, - { ContentType.Slm, "text/slim" }, - { ContentType.Sls, "application/route-s-tsid+xml" }, - { ContentType.Slt, "application/vnd.epson.salt" }, - { ContentType.Sm, "application/vnd.stepmania.stepchart" }, - { ContentType.Smf, "application/vnd.stardivision.math" }, - { ContentType.Smi, "application/smil+xml" }, - { ContentType.Smil, "application/smil+xml" }, - { ContentType.Smv, "video/x-smv" }, - { ContentType.Smzip, "application/vnd.stepmania.package" }, - { ContentType.Snd, "audio/basic" }, - { ContentType.Snf, "application/x-font-snf" }, - { ContentType.So, "application/octet-stream" }, - { ContentType.Spc, "application/x-pkcs7-certificates" }, - { ContentType.Spdx, "text/spdx" }, - { ContentType.Spf, "application/vnd.yamaha.smaf-phrase" }, - { ContentType.Spl, "application/x-futuresplash" }, - { ContentType.Spot, "text/vnd.in3d.spot" }, - { ContentType.Spp, "application/scvp-vp-response" }, - { ContentType.Spq, "application/scvp-vp-request" }, - { ContentType.Spx, "audio/ogg" }, - { ContentType.Sql, "application/x-sql" }, - { ContentType.Src, "application/x-wais-source" }, - { ContentType.Srt, "application/x-subrip" }, - { ContentType.Sru, "application/sru+xml" }, - { ContentType.Srx, "application/sparql-results+xml" }, - { ContentType.Ssdl, "application/ssdl+xml" }, - { ContentType.Sse, "application/vnd.kodak-descriptor" }, - { ContentType.Ssf, "application/vnd.epson.ssf" }, - { ContentType.Ssml, "application/ssml+xml" }, - { ContentType.St, "application/vnd.sailingtracker.track" }, - { ContentType.Stc, "application/vnd.sun.xml.calc.template" }, - { ContentType.Std, "application/vnd.sun.xml.draw.template" }, - { ContentType.Stf, "application/vnd.wt.stf" }, - { ContentType.Sti, "application/vnd.sun.xml.impress.template" }, - { ContentType.Stk, "application/hyperstudio" }, - { ContentType.Stl, "application/vnd.ms-pki.stl" }, - { ContentType.Stpx, "model/step+xml" }, - { ContentType.Stpxz, "model/step-xml+zip" }, - { ContentType.Stpz, "model/step+zip" }, - { ContentType.Str, "application/vnd.pg.format" }, - { ContentType.Stw, "application/vnd.sun.xml.writer.template" }, - { ContentType.Styl, "text/stylus" }, - { ContentType.Stylus, "text/stylus" }, - { ContentType.Sub, "image/vnd.dvb.subtitle" }, - { ContentType.Sus, "application/vnd.sus-calendar" }, - { ContentType.Susp, "application/vnd.sus-calendar" }, - { ContentType.Sv4cpio, "application/x-sv4cpio" }, - { ContentType.Sv4crc, "application/x-sv4crc" }, - { ContentType.Svc, "application/vnd.dvb.service" }, - { ContentType.Svd, "application/vnd.svd" }, - { ContentType.Svg, "image/svg+xml" }, - { ContentType.Svgz, "image/svg+xml" }, - { ContentType.Swa, "application/x-director" }, - { ContentType.Swf, "application/x-shockwave-flash" }, - { ContentType.Swi, "application/vnd.aristanetworks.swi" }, - { ContentType.Swidtag, "application/swid+xml" }, - { ContentType.Sxc, "application/vnd.sun.xml.calc" }, - { ContentType.Sxd, "application/vnd.sun.xml.draw" }, - { ContentType.Sxg, "application/vnd.sun.xml.writer.global" }, - { ContentType.Sxi, "application/vnd.sun.xml.impress" }, - { ContentType.Sxm, "application/vnd.sun.xml.math" }, - { ContentType.Sxw, "application/vnd.sun.xml.writer" }, - { ContentType.T, "text/troff" }, - { ContentType.T3, "application/x-t3vm-image" }, - { ContentType.T38, "image/t38" }, - { ContentType.Taglet, "application/vnd.mynfc" }, - { ContentType.Tao, "application/vnd.tao.intent-module-archive" }, - { ContentType.Tap, "image/vnd.tencent.tap" }, - { ContentType.Tar, "application/x-tar" }, - { ContentType.Tcap, "application/vnd.3gpp2.tcap" }, - { ContentType.Tcl, "application/x-tcl" }, - { ContentType.Td, "application/urc-targetdesc+xml" }, - { ContentType.Teacher, "application/vnd.smart.teacher" }, - { ContentType.Tei, "application/tei+xml" }, - { ContentType.Tex, "application/x-tex" }, - { ContentType.Texi, "application/x-texinfo" }, - { ContentType.Texinfo, "application/x-texinfo" }, - { ContentType.Text, "text/plain" }, - { ContentType.Tfi, "application/thraud+xml" }, - { ContentType.Tfm, "application/x-tex-tfm" }, - { ContentType.Tfx, "image/tiff-fx" }, - { ContentType.Tga, "image/x-tga" }, - { ContentType.Thmx, "application/vnd.ms-officetheme" }, - { ContentType.Tif, "image/tiff" }, - { ContentType.Tiff, "image/tiff" }, - { ContentType.Tk, "application/x-tcl" }, - { ContentType.Tmo, "application/vnd.tmobile-livetv" }, - { ContentType.Toml, "application/toml" }, - { ContentType.Torrent, "application/x-bittorrent" }, - { ContentType.Tpl, "application/vnd.groove-tool-template" }, - { ContentType.Tpt, "application/vnd.trid.tpt" }, - { ContentType.Tr, "text/troff" }, - { ContentType.Tra, "application/vnd.trueapp" }, - { ContentType.Trig, "application/trig" }, - { ContentType.Trm, "application/x-msterminal" }, - { ContentType.Ts, "video/mp2t" }, - { ContentType.Tsd, "application/timestamped-data" }, - { ContentType.Tsv, "text/tab-separated-values" }, - { ContentType.Ttc, "font/collection" }, - { ContentType.Ttf, "font/ttf" }, - { ContentType.Ttl, "text/turtle" }, - { ContentType.Ttml, "application/ttml+xml" }, - { ContentType.Twd, "application/vnd.simtech-mindmapper" }, - { ContentType.Twds, "application/vnd.simtech-mindmapper" }, - { ContentType.Txd, "application/vnd.genomatix.tuxedo" }, - { ContentType.Txf, "application/vnd.mobius.txf" }, - { ContentType.Txt, "text/plain" }, - { ContentType.U32, "application/x-authorware-bin" }, - { ContentType.U8dsn, "message/global-delivery-status" }, - { ContentType.U8hdr, "message/global-headers" }, - { ContentType.U8mdn, "message/global-disposition-notification" }, - { ContentType.U8msg, "message/global" }, - { ContentType.Ubj, "application/ubjson" }, - { ContentType.Udeb, "application/x-debian-package" }, - { ContentType.Ufd, "application/vnd.ufdl" }, - { ContentType.Ufdl, "application/vnd.ufdl" }, - { ContentType.Ulx, "application/x-glulx" }, - { ContentType.Umj, "application/vnd.umajin" }, - { ContentType.Unityweb, "application/vnd.unity" }, - { ContentType.Uoml, "application/vnd.uoml+xml" }, - { ContentType.Uri, "text/uri-list" }, - { ContentType.Uris, "text/uri-list" }, - { ContentType.Urls, "text/uri-list" }, - { ContentType.Usdz, "model/vnd.usdz+zip" }, - { ContentType.Ustar, "application/x-ustar" }, - { ContentType.Utz, "application/vnd.uiq.theme" }, - { ContentType.Uu, "text/x-uuencode" }, - { ContentType.Uva, "audio/vnd.dece.audio" }, - { ContentType.Uvd, "application/vnd.dece.data" }, - { ContentType.Uvf, "application/vnd.dece.data" }, - { ContentType.Uvg, "image/vnd.dece.graphic" }, - { ContentType.Uvh, "video/vnd.dece.hd" }, - { ContentType.Uvi, "image/vnd.dece.graphic" }, - { ContentType.Uvm, "video/vnd.dece.mobile" }, - { ContentType.Uvp, "video/vnd.dece.pd" }, - { ContentType.Uvs, "video/vnd.dece.sd" }, - { ContentType.Uvt, "application/vnd.dece.ttml+xml" }, - { ContentType.Uvu, "video/vnd.uvvu.mp4" }, - { ContentType.Uvv, "video/vnd.dece.video" }, - { ContentType.Uvva, "audio/vnd.dece.audio" }, - { ContentType.Uvvd, "application/vnd.dece.data" }, - { ContentType.Uvvf, "application/vnd.dece.data" }, - { ContentType.Uvvg, "image/vnd.dece.graphic" }, - { ContentType.Uvvh, "video/vnd.dece.hd" }, - { ContentType.Uvvi, "image/vnd.dece.graphic" }, - { ContentType.Uvvm, "video/vnd.dece.mobile" }, - { ContentType.Uvvp, "video/vnd.dece.pd" }, - { ContentType.Uvvs, "video/vnd.dece.sd" }, - { ContentType.Uvvt, "application/vnd.dece.ttml+xml" }, - { ContentType.Uvvu, "video/vnd.uvvu.mp4" }, - { ContentType.Uvvv, "video/vnd.dece.video" }, - { ContentType.Uvvx, "application/vnd.dece.unspecified" }, - { ContentType.Uvvz, "application/vnd.dece.zip" }, - { ContentType.Uvx, "application/vnd.dece.unspecified" }, - { ContentType.Uvz, "application/vnd.dece.zip" }, - { ContentType.Vbox, "application/x-virtualbox-vbox" }, - { ContentType.Vcard, "text/vcard" }, - { ContentType.Vcd, "application/x-cdlink" }, - { ContentType.Vcf, "text/x-vcard" }, - { ContentType.Vcg, "application/vnd.groove-vcard" }, - { ContentType.Vcs, "text/x-vcalendar" }, - { ContentType.Vcx, "application/vnd.vcx" }, - { ContentType.Vdi, "application/x-virtualbox-vdi" }, - { ContentType.Vds, "model/vnd.sap.vds" }, - { ContentType.Vhd, "application/x-virtualbox-vhd" }, - { ContentType.Vis, "application/vnd.visionary" }, - { ContentType.Viv, "video/vnd.vivo" }, - { ContentType.Vmdk, "application/x-virtualbox-vmdk" }, - { ContentType.Vob, "video/x-ms-vob" }, - { ContentType.Vor, "application/vnd.stardivision.writer" }, - { ContentType.Vox, "application/x-authorware-bin" }, - { ContentType.Vrml, "model/vrml" }, - { ContentType.Vsd, "application/vnd.visio" }, - { ContentType.Vsf, "application/vnd.vsf" }, - { ContentType.Vss, "application/vnd.visio" }, - { ContentType.Vst, "application/vnd.visio" }, - { ContentType.Vsw, "application/vnd.visio" }, - { ContentType.Vtf, "image/vnd.valve.source.texture" }, - { ContentType.Vtt, "text/vtt" }, - { ContentType.Vtu, "model/vnd.vtu" }, - { ContentType.Vxml, "application/voicexml+xml" }, - { ContentType.W3d, "application/x-director" }, - { ContentType.Wad, "application/x-doom" }, - { ContentType.Wadl, "application/vnd.sun.wadl+xml" }, - { ContentType.War, "application/java-archive" }, - { ContentType.Wasm, "application/wasm" }, - { ContentType.Wav, "audio/wav" }, - { ContentType.Wax, "audio/x-ms-wax" }, - { ContentType.Wbmp, "image/vnd.wap.wbmp" }, - { ContentType.Wbs, "application/vnd.criticaltools.wbs+xml" }, - { ContentType.Wbxml, "application/vnd.wap.wbxml" }, - { ContentType.Wcm, "application/vnd.ms-works" }, - { ContentType.Wdb, "application/vnd.ms-works" }, - { ContentType.Wdp, "image/vnd.ms-photo" }, - { ContentType.Weba, "audio/webm" }, - { ContentType.Webapp, "application/x-web-app-manifest+json" }, - { ContentType.Webm, "video/webm" }, - { ContentType.Webp, "image/webp" }, - { ContentType.Wg, "application/vnd.pmi.widget" }, - { ContentType.Wgt, "application/widget" }, - { ContentType.Wks, "application/vnd.ms-works" }, - { ContentType.Wm, "video/x-ms-wm" }, - { ContentType.Wma, "audio/x-ms-wma" }, - { ContentType.Wmd, "application/x-ms-wmd" }, - { ContentType.Wmf, "application/x-msmetafile" }, - { ContentType.Wml, "text/vnd.wap.wml" }, - { ContentType.Wmlc, "application/vnd.wap.wmlc" }, - { ContentType.Wmls, "text/vnd.wap.wmlscript" }, - { ContentType.Wmlsc, "application/vnd.wap.wmlscriptc" }, - { ContentType.Wmv, "video/x-ms-wmv" }, - { ContentType.Wmx, "video/x-ms-wmx" }, - { ContentType.Wmz, "application/x-ms-wmz" }, - { ContentType.Woff, "font/woff" }, - { ContentType.Woff2, "font/woff2" }, - { ContentType.Wpd, "application/vnd.wordperfect" }, - { ContentType.Wpl, "application/vnd.ms-wpl" }, - { ContentType.Wps, "application/vnd.ms-works" }, - { ContentType.Wqd, "application/vnd.wqd" }, - { ContentType.Wri, "application/x-mswrite" }, - { ContentType.Wrl, "model/vrml" }, - { ContentType.Wsc, "message/vnd.wfa.wsc" }, - { ContentType.Wsdl, "application/wsdl+xml" }, - { ContentType.Wspolicy, "application/wspolicy+xml" }, - { ContentType.Wtb, "application/vnd.webturbo" }, - { ContentType.Wvx, "video/x-ms-wvx" }, - { ContentType.X32, "application/x-authorware-bin" }, - { ContentType.X3d, "model/x3d+xml" }, - { ContentType.X3db, "model/x3d+binary" }, - { ContentType.X3dbz, "model/x3d+binary" }, - { ContentType.X3dv, "model/x3d+vrml" }, - { ContentType.X3dvz, "model/x3d+vrml" }, - { ContentType.X3dz, "model/x3d+xml" }, - { ContentType.Xaml, "application/xaml+xml" }, - { ContentType.Xap, "application/x-silverlight-app" }, - { ContentType.Xar, "application/vnd.xara" }, - { ContentType.Xav, "application/xcap-att+xml" }, - { ContentType.Xbap, "application/x-ms-xbap" }, - { ContentType.Xbd, "application/vnd.fujixerox.docuworks.binder" }, - { ContentType.Xbm, "image/x-xbitmap" }, - { ContentType.Xca, "application/xcap-caps+xml" }, - { ContentType.Xcs, "application/calendar+xml" }, - { ContentType.Xdf, "application/xcap-diff+xml" }, - { ContentType.Xdm, "application/vnd.syncml.dm+xml" }, - { ContentType.Xdp, "application/vnd.adobe.xdp+xml" }, - { ContentType.Xdssc, "application/dssc+xml" }, - { ContentType.Xdw, "application/vnd.fujixerox.docuworks" }, - { ContentType.Xel, "application/xcap-el+xml" }, - { ContentType.Xenc, "application/xenc+xml" }, - { ContentType.Xer, "application/patch-ops-error+xml" }, - { ContentType.Xfdf, "application/vnd.adobe.xfdf" }, - { ContentType.Xfdl, "application/vnd.xfdl" }, - { ContentType.Xht, "application/xhtml+xml" }, - { ContentType.Xhtml, "application/xhtml+xml" }, - { ContentType.Xhvml, "application/xv+xml" }, - { ContentType.Xif, "image/vnd.xiff" }, - { ContentType.Xla, "application/vnd.ms-excel" }, - { ContentType.Xlam, "application/vnd.ms-excel.addin.macroenabled.12" }, - { ContentType.Xlc, "application/vnd.ms-excel" }, - { ContentType.Xlf, "application/x-xliff+xml" }, - { ContentType.Xlm, "application/vnd.ms-excel" }, - { ContentType.Xls, "application/vnd.ms-excel" }, - { ContentType.Xlsb, "application/vnd.ms-excel.sheet.binary.macroenabled.12" }, - { ContentType.Xlsm, "application/vnd.ms-excel.sheet.macroenabled.12" }, - { ContentType.Xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, - { ContentType.Xlt, "application/vnd.ms-excel" }, - { ContentType.Xltm, "application/vnd.ms-excel.template.macroenabled.12" }, - { ContentType.Xltx, "application/vnd.openxmlformats-officedocument.spreadsheetml.template" }, - { ContentType.Xlw, "application/vnd.ms-excel" }, - { ContentType.Xm, "audio/xm" }, - { ContentType.Xml, "application/xml" }, - { ContentType.Xns, "application/xcap-ns+xml" }, - { ContentType.Xo, "application/vnd.olpc-sugar" }, - { ContentType.Xop, "application/xop+xml" }, - { ContentType.Xpi, "application/x-xpinstall" }, - { ContentType.Xpl, "application/xproc+xml" }, - { ContentType.Xpm, "image/x-xpixmap" }, - { ContentType.Xpr, "application/vnd.is-xpr" }, - { ContentType.Xps, "application/vnd.ms-xpsdocument" }, - { ContentType.Xpw, "application/vnd.intercon.formnet" }, - { ContentType.Xpx, "application/vnd.intercon.formnet" }, - { ContentType.Xsd, "application/xml" }, - { ContentType.Xsl, "application/xml" }, - { ContentType.Xslt, "application/xslt+xml" }, - { ContentType.Xsm, "application/vnd.syncml+xml" }, - { ContentType.Xspf, "application/xspf+xml" }, - { ContentType.Xul, "application/vnd.mozilla.xul+xml" }, - { ContentType.Xvm, "application/xv+xml" }, - { ContentType.Xvml, "application/xv+xml" }, - { ContentType.Xwd, "image/x-xwindowdump" }, - { ContentType.Xyz, "chemical/x-xyz" }, - { ContentType.Xz, "application/x-xz" }, - { ContentType.Yaml, "text/yaml" }, - { ContentType.Yang, "application/yang" }, - { ContentType.Yin, "application/yin+xml" }, - { ContentType.Yml, "text/yaml" }, - { ContentType.Ymp, "text/x-suse-ymp" }, - { ContentType.Z1, "application/x-zmachine" }, - { ContentType.Z2, "application/x-zmachine" }, - { ContentType.Z3, "application/x-zmachine" }, - { ContentType.Z4, "application/x-zmachine" }, - { ContentType.Z5, "application/x-zmachine" }, - { ContentType.Z6, "application/x-zmachine" }, - { ContentType.Z7, "application/x-zmachine" }, - { ContentType.Z8, "application/x-zmachine" }, - { ContentType.Zaz, "application/vnd.zzazz.deck+xml" }, - { ContentType.Zip, "application/zip" }, - { ContentType.Zir, "application/vnd.zul" }, - { ContentType.Zirz, "application/vnd.zul" }, - { ContentType.Zmm, "application/vnd.handheld-entertainment+xml" }, - }; - private static readonly IReadOnlyDictionary<string, ContentType> ExtensionToCt = new Dictionary<string, ContentType>() - { - { "aab", ContentType.Aab }, - { "aac", ContentType.Aac }, - { "aam", ContentType.Aam }, - { "aas", ContentType.Aas }, - { "abw", ContentType.Abw }, - { "ac", ContentType.Ac }, - { "acc", ContentType.Acc }, - { "ace", ContentType.Ace }, - { "acu", ContentType.Acu }, - { "acutc", ContentType.Acutc }, - { "adp", ContentType.Adp }, - { "aep", ContentType.Aep }, - { "afm", ContentType.Afm }, - { "afp", ContentType.Afp }, - { "ahead", ContentType.Ahead }, - { "ai", ContentType.Ai }, - { "aif", ContentType.Aif }, - { "aifc", ContentType.Aifc }, - { "aiff", ContentType.Aiff }, - { "air", ContentType.Air }, - { "ait", ContentType.Ait }, - { "ami", ContentType.Ami }, - { "amr", ContentType.Amr }, - { "apk", ContentType.Apk }, - { "apng", ContentType.Apng }, - { "appcache", ContentType.Appcache }, - { "apr", ContentType.Apr }, - { "arc", ContentType.Arc }, - { "arj", ContentType.Arj }, - { "asc", ContentType.Asc }, - { "asf", ContentType.Asf }, - { "asm", ContentType.Asm }, - { "aso", ContentType.Aso }, - { "asx", ContentType.Asx }, - { "atc", ContentType.Atc }, - { "atom", ContentType.Atom }, - { "atomcat", ContentType.Atomcat }, - { "atomsvc", ContentType.Atomsvc }, - { "atx", ContentType.Atx }, - { "au", ContentType.Au }, - { "avi", ContentType.Avi }, - { "avif", ContentType.Avif }, - { "aw", ContentType.Aw }, - { "azf", ContentType.Azf }, - { "azs", ContentType.Azs }, - { "azv", ContentType.Azv }, - { "azw", ContentType.Azw }, - { "b16", ContentType.B16 }, - { "bat", ContentType.Bat }, - { "bcpio", ContentType.Bcpio }, - { "bdf", ContentType.Bdf }, - { "bdm", ContentType.Bdm }, - { "bdoc", ContentType.Bdoc }, - { "bed", ContentType.Bed }, - { "bh2", ContentType.Bh2 }, - { "bin", ContentType.Binary }, - { "blb", ContentType.Blb }, - { "blorb", ContentType.Blorb }, - { "bmi", ContentType.Bmi }, - { "bmml", ContentType.Bmml }, - { "bmp", ContentType.Bmp }, - { "book", ContentType.Book }, - { "box", ContentType.Box }, - { "boz", ContentType.Boz }, - { "bpk", ContentType.Bpk }, - { "bsp", ContentType.Bsp }, - { "btif", ContentType.Btif }, - { "buffer", ContentType.Buffer }, - { "bz", ContentType.Bz }, - { "bz2", ContentType.Bz2 }, - { "c", ContentType.C }, - { "c11amc", ContentType.C11amc }, - { "c11amz", ContentType.C11amz }, - { "c4d", ContentType.C4d }, - { "c4f", ContentType.C4f }, - { "c4g", ContentType.C4g }, - { "c4p", ContentType.C4p }, - { "c4u", ContentType.C4u }, - { "cab", ContentType.Cab }, - { "caf", ContentType.Caf }, - { "cap", ContentType.Cap }, - { "car", ContentType.Car }, - { "cat", ContentType.Cat }, - { "cb7", ContentType.Cb7 }, - { "cba", ContentType.Cba }, - { "cbr", ContentType.Cbr }, - { "cbt", ContentType.Cbt }, - { "cbz", ContentType.Cbz }, - { "cc", ContentType.Cc }, - { "cco", ContentType.Cco }, - { "cct", ContentType.Cct }, - { "ccxml", ContentType.Ccxml }, - { "cdbcmsg", ContentType.Cdbcmsg }, - { "cdf", ContentType.Cdf }, - { "cdfx", ContentType.Cdfx }, - { "cdkey", ContentType.Cdkey }, - { "cdmia", ContentType.Cdmia }, - { "cdmic", ContentType.Cdmic }, - { "cdmid", ContentType.Cdmid }, - { "cdmio", ContentType.Cdmio }, - { "cdmiq", ContentType.Cdmiq }, - { "cdx", ContentType.Cdx }, - { "cdxml", ContentType.Cdxml }, - { "cdy", ContentType.Cdy }, - { "cer", ContentType.Cer }, - { "cfs", ContentType.Cfs }, - { "cgm", ContentType.Cgm }, - { "chat", ContentType.Chat }, - { "chm", ContentType.Chm }, - { "chrt", ContentType.Chrt }, - { "cif", ContentType.Cif }, - { "cii", ContentType.Cii }, - { "cil", ContentType.Cil }, - { "cjs", ContentType.Cjs }, - { "cla", ContentType.Cla }, - { "clkk", ContentType.Clkk }, - { "clkp", ContentType.Clkp }, - { "clkt", ContentType.Clkt }, - { "clkw", ContentType.Clkw }, - { "clkx", ContentType.Clkx }, - { "clp", ContentType.Clp }, - { "cmc", ContentType.Cmc }, - { "cmdf", ContentType.Cmdf }, - { "cml", ContentType.Cml }, - { "cmp", ContentType.Cmp }, - { "cmx", ContentType.Cmx }, - { "cod", ContentType.Cod }, - { "coffee", ContentType.Coffee }, - { "com", ContentType.Com }, - { "conf", ContentType.Conf }, - { "cpio", ContentType.Cpio }, - { "cpp", ContentType.Cpp }, - { "cpt", ContentType.Cpt }, - { "crd", ContentType.Crd }, - { "crl", ContentType.Crl }, - { "crt", ContentType.Crt }, - { "crx", ContentType.Crx }, - { "csh", ContentType.Csh }, - { "csl", ContentType.Csl }, - { "csml", ContentType.Csml }, - { "csp", ContentType.Csp }, - { "css", ContentType.Css }, - { "cst", ContentType.Cst }, - { "csv", ContentType.Csv }, - { "cu", ContentType.Cu }, - { "curl", ContentType.Curl }, - { "cww", ContentType.Cww }, - { "cxt", ContentType.Cxt }, - { "cxx", ContentType.Cxx }, - { "dae", ContentType.Dae }, - { "daf", ContentType.Daf }, - { "dart", ContentType.Dart }, - { "dataless", ContentType.Dataless }, - { "davmount", ContentType.Davmount }, - { "dbf", ContentType.Dbf }, - { "dbk", ContentType.Dbk }, - { "dcr", ContentType.Dcr }, - { "dcurl", ContentType.Dcurl }, - { "dd2", ContentType.Dd2 }, - { "ddd", ContentType.Ddd }, - { "ddf", ContentType.Ddf }, - { "dds", ContentType.Dds }, - { "deb", ContentType.Deb }, - { "def", ContentType.Def }, - { "deploy", ContentType.Deploy }, - { "der", ContentType.Der }, - { "dfac", ContentType.Dfac }, - { "dgc", ContentType.Dgc }, - { "dic", ContentType.Dic }, - { "dir", ContentType.Dir }, - { "dis", ContentType.Dis }, - { "dist", ContentType.Dist }, - { "distz", ContentType.Distz }, - { "djv", ContentType.Djv }, - { "djvu", ContentType.Djvu }, - { "dll", ContentType.Dll }, - { "dmg", ContentType.Dmg }, - { "dmp", ContentType.Dmp }, - { "dms", ContentType.Dms }, - { "dna", ContentType.Dna }, - { "doc", ContentType.Doc }, - { "docm", ContentType.Docm }, - { "docx", ContentType.Docx }, - { "dot", ContentType.Dot }, - { "dotm", ContentType.Dotm }, - { "dotx", ContentType.Dotx }, - { "dp", ContentType.Dp }, - { "dpg", ContentType.Dpg }, - { "dra", ContentType.Dra }, - { "drle", ContentType.Drle }, - { "dsc", ContentType.Dsc }, - { "dssc", ContentType.Dssc }, - { "dtb", ContentType.Dtb }, - { "dtd", ContentType.Dtd }, - { "dts", ContentType.Dts }, - { "dtshd", ContentType.Dtshd }, - { "dump", ContentType.Dump }, - { "dvb", ContentType.Dvb }, - { "dvi", ContentType.Dvi }, - { "dwd", ContentType.Dwd }, - { "dwf", ContentType.Dwf }, - { "dwg", ContentType.Dwg }, - { "dxf", ContentType.Dxf }, - { "dxp", ContentType.Dxp }, - { "dxr", ContentType.Dxr }, - { "ear", ContentType.Ear }, - { "ecma", ContentType.Ecma }, - { "edm", ContentType.Edm }, - { "edx", ContentType.Edx }, - { "efif", ContentType.Efif }, - { "ei6", ContentType.Ei6 }, - { "elc", ContentType.Elc }, - { "emf", ContentType.Emf }, - { "eml", ContentType.Eml }, - { "emma", ContentType.Emma }, - { "emz", ContentType.Emz }, - { "eol", ContentType.Eol }, - { "eot", ContentType.Eot }, - { "eps", ContentType.Eps }, - { "epub", ContentType.Epub }, - { "es", ContentType.Es }, - { "es3", ContentType.Es3 }, - { "esa", ContentType.Esa }, - { "esf", ContentType.Esf }, - { "et3", ContentType.Et3 }, - { "etx", ContentType.Etx }, - { "eva", ContentType.Eva }, - { "evy", ContentType.Evy }, - { "exe", ContentType.Exe }, - { "exi", ContentType.Exi }, - { "exp", ContentType.Exp }, - { "exr", ContentType.Exr }, - { "ext", ContentType.Ext }, - { "ez", ContentType.Ez }, - { "ez2", ContentType.Ez2 }, - { "ez3", ContentType.Ez3 }, - { "f", ContentType.F }, - { "f4v", ContentType.F4v }, - { "f77", ContentType.Fortran }, - { "f90", ContentType.F90 }, - { "fbs", ContentType.Fbs }, - { "fcdt", ContentType.Fcdt }, - { "fcs", ContentType.Fcs }, - { "fdf", ContentType.Fdf }, - { "fdt", ContentType.Fdt }, - { "fg5", ContentType.Fg5 }, - { "fgd", ContentType.Fgd }, - { "fh", ContentType.Fh }, - { "fh4", ContentType.Fh4 }, - { "fh5", ContentType.Fh5 }, - { "fh7", ContentType.Fh7 }, - { "fhc", ContentType.Fhc }, - { "fig", ContentType.Fig }, - { "fits", ContentType.Fits }, - { "flac", ContentType.Flac }, - { "fli", ContentType.Fli }, - { "flo", ContentType.Flo }, - { "flv", ContentType.Flv }, - { "flw", ContentType.Flw }, - { "flx", ContentType.Flx }, - { "fly", ContentType.Fly }, - { "fm", ContentType.Fm }, - { "fnc", ContentType.Fnc }, - { "fo", ContentType.Fo }, - { "for", ContentType.For }, - { "fpx", ContentType.Fpx }, - { "frame", ContentType.Frame }, - { "fsc", ContentType.Fsc }, - { "fst", ContentType.Fst }, - { "ftc", ContentType.Ftc }, - { "fti", ContentType.Fti }, - { "fvt", ContentType.Fvt }, - { "fxp", ContentType.Fxp }, - { "fxpl", ContentType.Fxpl }, - { "fzs", ContentType.Fzs }, - { "g2w", ContentType.G2w }, - { "g3", ContentType.G3 }, - { "g3w", ContentType.G3w }, - { "gac", ContentType.Gac }, - { "gam", ContentType.Gam }, - { "gbr", ContentType.Gbr }, - { "gca", ContentType.Gca }, - { "gdl", ContentType.Gdl }, - { "gdoc", ContentType.Gdoc }, - { "geo", ContentType.Geo }, - { "geojson", ContentType.Geojson }, - { "gex", ContentType.Gex }, - { "ggb", ContentType.Ggb }, - { "ggt", ContentType.Ggt }, - { "ghf", ContentType.Ghf }, - { "gif", ContentType.Gif }, - { "gim", ContentType.Gim }, - { "glb", ContentType.Glb }, - { "gltf", ContentType.Gltf }, - { "gml", ContentType.Gml }, - { "gmx", ContentType.Gmx }, - { "gnumeric", ContentType.Gnumeric }, - { "gph", ContentType.Gph }, - { "gpx", ContentType.Gpx }, - { "gqf", ContentType.Gqf }, - { "gqs", ContentType.Gqs }, - { "gram", ContentType.Gram }, - { "gramps", ContentType.Gramps }, - { "gre", ContentType.Gre }, - { "grv", ContentType.Grv }, - { "grxml", ContentType.Grxml }, - { "gsf", ContentType.Gsf }, - { "gsheet", ContentType.Gsheet }, - { "gslides", ContentType.Gslides }, - { "gtar", ContentType.Gtar }, - { "gtm", ContentType.Gtm }, - { "gtw", ContentType.Gtw }, - { "gv", ContentType.Gv }, - { "gxf", ContentType.Gxf }, - { "gxt", ContentType.Gxt }, - { "gz", ContentType.Gz }, - { "h", ContentType.H }, - { "h261", ContentType.H261 }, - { "h263", ContentType.H263 }, - { "h264", ContentType.H264 }, - { "hal", ContentType.Hal }, - { "hbci", ContentType.Hbci }, - { "hbs", ContentType.Hbs }, - { "hdd", ContentType.Hdd }, - { "hdf", ContentType.Hdf }, - { "heic", ContentType.Heic }, - { "heics", ContentType.Heics }, - { "heif", ContentType.Heif }, - { "heifs", ContentType.Heifs }, - { "hej2", ContentType.Hej2 }, - { "held", ContentType.Held }, - { "hh", ContentType.Hh }, - { "hjson", ContentType.Hjson }, - { "hlp", ContentType.Hlp }, - { "hpgl", ContentType.Hpgl }, - { "hpid", ContentType.Hpid }, - { "hps", ContentType.Hps }, - { "hqx", ContentType.Hqx }, - { "hsj2", ContentType.Hsj2 }, - { "htc", ContentType.Htc }, - { "htke", ContentType.Htke }, - { "htm", ContentType.Htm }, - { "html", ContentType.Html }, - { "hvd", ContentType.Hvd }, - { "hvp", ContentType.Hvp }, - { "hex", ContentType.Binary }, - { "hvs", ContentType.Hvs }, - { "i2g", ContentType.I2g }, - { "icc", ContentType.Icc }, - { "ice", ContentType.Ice }, - { "icm", ContentType.Icm }, - { "ico", ContentType.Ico }, - { "ics", ContentType.Ics }, - { "ief", ContentType.Ief }, - { "ifb", ContentType.Ifb }, - { "ifm", ContentType.Ifm }, - { "iges", ContentType.Iges }, - { "igl", ContentType.Igl }, - { "igm", ContentType.Igm }, - { "igs", ContentType.Igs }, - { "igx", ContentType.Igx }, - { "iif", ContentType.Iif }, - { "img", ContentType.Img }, - { "imp", ContentType.Imp }, - { "ims", ContentType.Ims }, - { "ini", ContentType.Ini }, - { "ink", ContentType.Ink }, - { "inkml", ContentType.Inkml }, - { "install", ContentType.Install }, - { "iota", ContentType.Iota }, - { "ipfix", ContentType.Ipfix }, - { "ipk", ContentType.Ipk }, - { "irm", ContentType.Irm }, - { "irp", ContentType.Irp }, - { "iso", ContentType.Iso }, - { "itp", ContentType.Itp }, - { "its", ContentType.Its }, - { "ivp", ContentType.Ivp }, - { "ivu", ContentType.Ivu }, - { "jad", ContentType.Jad }, - { "jade", ContentType.Jade }, - { "jam", ContentType.Jam }, - { "jar", ContentType.Jar }, - { "jardiff", ContentType.Jardiff }, - { "java", ContentType.Java }, - { "jhc", ContentType.Jhc }, - { "jisp", ContentType.Jisp }, - { "jls", ContentType.Jls }, - { "jlt", ContentType.Jlt }, - { "jng", ContentType.Jng }, - { "jnlp", ContentType.Jnlp }, - { "joda", ContentType.Joda }, - { "jp2", ContentType.Jp2 }, - { "jpe", ContentType.Jpe }, - { "jpeg", ContentType.Jpeg }, - { "jpf", ContentType.Jpf }, - { "jpg", ContentType.Jpg }, - { "jpg2", ContentType.Jpg2 }, - { "jpgm", ContentType.Jpgm }, - { "jpgv", ContentType.Jpgv }, - { "jph", ContentType.Jph }, - { "jpm", ContentType.Jpm }, - { "jpx", ContentType.Jpx }, - { "js", ContentType.Javascript }, - { "json", ContentType.Json }, - { "json5", ContentType.Json5 }, - { "jsonld", ContentType.Jsonld }, - { "jsonml", ContentType.Jsonml }, - { "jsx", ContentType.Jsx }, - { "jxr", ContentType.Jxr }, - { "jxra", ContentType.Jxra }, - { "jxrs", ContentType.Jxrs }, - { "jxs", ContentType.Jxs }, - { "jxsc", ContentType.Jxsc }, - { "jxsi", ContentType.Jxsi }, - { "jxss", ContentType.Jxss }, - { "kar", ContentType.Kar }, - { "karbon", ContentType.Karbon }, - { "kdbx", ContentType.Kdbx }, - { "key", ContentType.Key }, - { "kfo", ContentType.Kfo }, - { "kia", ContentType.Kia }, - { "kml", ContentType.Kml }, - { "kmz", ContentType.Kmz }, - { "kne", ContentType.Kne }, - { "knp", ContentType.Knp }, - { "kon", ContentType.Kon }, - { "kpr", ContentType.Kpr }, - { "kpt", ContentType.Kpt }, - { "kpxx", ContentType.Kpxx }, - { "ksp", ContentType.Ksp }, - { "ktr", ContentType.Ktr }, - { "ktx", ContentType.Ktx }, - { "ktx2", ContentType.Ktx2 }, - { "ktz", ContentType.Ktz }, - { "kwd", ContentType.Kwd }, - { "kwt", ContentType.Kwt }, - { "lasxml", ContentType.Lasxml }, - { "latex", ContentType.Latex }, - { "lbd", ContentType.Lbd }, - { "lbe", ContentType.Lbe }, - { "les", ContentType.Les }, - { "less", ContentType.Less }, - { "lgr", ContentType.Lgr }, - { "lha", ContentType.Lha }, - { "link66", ContentType.Link66 }, - { "list", ContentType.List }, - { "list3820", ContentType.List3820 }, - { "listafp", ContentType.Listafp }, - { "lnk", ContentType.Lnk }, - { "log", ContentType.Log }, - { "lostxml", ContentType.Lostxml }, - { "lrf", ContentType.Lrf }, - { "lrm", ContentType.Lrm }, - { "ltf", ContentType.Ltf }, - { "lua", ContentType.Lua }, - { "luac", ContentType.Luac }, - { "lvp", ContentType.Lvp }, - { "lwp", ContentType.Lwp }, - { "lzh", ContentType.Lzh }, - { "m13", ContentType.M13 }, - { "m14", ContentType.M14 }, - { "m1v", ContentType.M1v }, - { "m21", ContentType.M21 }, - { "m2a", ContentType.M2a }, - { "m2v", ContentType.M2v }, - { "m3a", ContentType.M3a }, - { "m3u", ContentType.M3u }, - { "m3u8", ContentType.M3u8 }, - { "m4a", ContentType.M4a }, - { "m4p", ContentType.M4p }, - { "m4s", ContentType.M4s }, - { "m4u", ContentType.M4u }, - { "m4v", ContentType.M4v }, - { "ma", ContentType.Ma }, - { "mads", ContentType.Mads }, - { "maei", ContentType.Maei }, - { "mag", ContentType.Mag }, - { "maker", ContentType.Maker }, - { "man", ContentType.Man }, - { "manifest", ContentType.Manifest }, - { "map", ContentType.Map }, - { "mar", ContentType.Mar }, - { "markdown", ContentType.Markdown }, - { "mathml", ContentType.Mathml }, - { "mb", ContentType.Mb }, - { "mbk", ContentType.Mbk }, - { "mbox", ContentType.Mbox }, - { "mc1", ContentType.Mc1 }, - { "mcd", ContentType.Mcd }, - { "mcurl", ContentType.Mcurl }, - { "md", ContentType.Md }, - { "mdb", ContentType.Mdb }, - { "mdi", ContentType.Mdi }, - { "mdx", ContentType.Mdx }, - { "me", ContentType.Me }, - { "mesh", ContentType.Mesh }, - { "meta4", ContentType.Meta4 }, - { "metalink", ContentType.Metalink }, - { "mets", ContentType.Mets }, - { "mfm", ContentType.Mfm }, - { "mft", ContentType.Mft }, - { "mgp", ContentType.Mgp }, - { "mgz", ContentType.Mgz }, - { "mid", ContentType.Mid }, - { "midi", ContentType.Midi }, - { "mie", ContentType.Mie }, - { "mif", ContentType.Mif }, - { "mime", ContentType.Mime }, - { "mj2", ContentType.Mj2 }, - { "mjp2", ContentType.Mjp2 }, - { "mjs", ContentType.Mjs }, - { "mk3d", ContentType.Mk3d }, - { "mka", ContentType.Mka }, - { "mkd", ContentType.Mkd }, - { "mks", ContentType.Mks }, - { "mkv", ContentType.Mkv }, - { "mlp", ContentType.Mlp }, - { "mmd", ContentType.Mmd }, - { "mmf", ContentType.Mmf }, - { "mml", ContentType.Mml }, - { "mmr", ContentType.Mmr }, - { "mng", ContentType.Mng }, - { "mny", ContentType.Mny }, - { "mobi", ContentType.Mobi }, - { "mods", ContentType.Mods }, - { "mov", ContentType.Mov }, - { "movie", ContentType.Movie }, - { "mp2", ContentType.Mp2 }, - { "mp21", ContentType.Mp21 }, - { "mp2a", ContentType.Mp2a }, - { "mp3", ContentType.Mp3 }, - { "mp4", ContentType.Mp4 }, - { "mp4a", ContentType.Mp4a }, - { "mp4s", ContentType.Mp4s }, - { "mp4v", ContentType.Mp4v }, - { "mpc", ContentType.Mpc }, - { "mpd", ContentType.Mpd }, - { "mpe", ContentType.Mpe }, - { "mpeg", ContentType.Mpeg }, - { "mpg", ContentType.Mpg }, - { "mpg4", ContentType.Mpg4 }, - { "mpga", ContentType.Mpga }, - { "mpkg", ContentType.Mpkg }, - { "mpm", ContentType.Mpm }, - { "mpn", ContentType.Mpn }, - { "mpp", ContentType.Mpp }, - { "mpt", ContentType.Mpt }, - { "mpy", ContentType.Mpy }, - { "mqy", ContentType.Mqy }, - { "mrc", ContentType.Mrc }, - { "mrcx", ContentType.Mrcx }, - { "ms", ContentType.Ms }, - { "mscml", ContentType.Mscml }, - { "mseed", ContentType.Mseed }, - { "mseq", ContentType.Mseq }, - { "msf", ContentType.Msf }, - { "msg", ContentType.Msg }, - { "msh", ContentType.Msh }, - { "msi", ContentType.Msi }, - { "msl", ContentType.Msl }, - { "msm", ContentType.Msm }, - { "msp", ContentType.Msp }, - { "msty", ContentType.Msty }, - { "mtl", ContentType.Mtl }, - { "mts", ContentType.Mts }, - { "mus", ContentType.Mus }, - { "musd", ContentType.Musd }, - { "musicxml", ContentType.Musicxml }, - { "mvb", ContentType.Mvb }, - { "mvt", ContentType.Mvt }, - { "mwf", ContentType.Mwf }, - { "mxf", ContentType.Mxf }, - { "mxl", ContentType.Mxl }, - { "mxmf", ContentType.Mxmf }, - { "mxml", ContentType.Mxml }, - { "mxs", ContentType.Mxs }, - { "mxu", ContentType.Mxu }, - { "n3", ContentType.N3 }, - { "nb", ContentType.Nb }, - { "nbp", ContentType.Nbp }, - { "nc", ContentType.Nc }, - { "ncx", ContentType.Ncx }, - { "nfo", ContentType.Nfo }, - { "ngdat", ContentType.Ngdat }, - { "nitf", ContentType.Nitf }, - { "nlu", ContentType.Nlu }, - { "nml", ContentType.Nml }, - { "nnd", ContentType.Nnd }, - { "nns", ContentType.Nns }, - { "nnw", ContentType.Nnw }, - { "npx", ContentType.Npx }, - { "nq", ContentType.Nq }, - { "nsc", ContentType.Nsc }, - { "nsf", ContentType.Nsf }, - { "nt", ContentType.Nt }, - { "ntf", ContentType.Ntf }, - { "numbers", ContentType.Numbers }, - { "nzb", ContentType.Nzb }, - { "oa2", ContentType.Oa2 }, - { "oa3", ContentType.Oa3 }, - { "oas", ContentType.Oas }, - { "obd", ContentType.Obd }, - { "obgx", ContentType.Obgx }, - { "obj", ContentType.Obj }, - { "oda", ContentType.Oda }, - { "odb", ContentType.Odb }, - { "odc", ContentType.Odc }, - { "odf", ContentType.Odf }, - { "odft", ContentType.Odft }, - { "odg", ContentType.Odg }, - { "odi", ContentType.Odi }, - { "odm", ContentType.Odm }, - { "odp", ContentType.Odp }, - { "ods", ContentType.Ods }, - { "odt", ContentType.Odt }, - { "oga", ContentType.Oga }, - { "ogex", ContentType.Ogex }, - { "ogg", ContentType.Ogg }, - { "ogv", ContentType.Ogv }, - { "ogx", ContentType.Ogx }, - { "omdoc", ContentType.Omdoc }, - { "onepkg", ContentType.Onepkg }, - { "onetmp", ContentType.Onetmp }, - { "onetoc", ContentType.Onetoc }, - { "onetoc2", ContentType.Onetoc2 }, - { "opf", ContentType.Opf }, - { "opml", ContentType.Opml }, - { "oprc", ContentType.Oprc }, - { "opus", ContentType.Opus }, - { "org", ContentType.Org }, - { "osf", ContentType.Osf }, - { "osfpvg", ContentType.Osfpvg }, - { "osm", ContentType.Osm }, - { "otc", ContentType.Otc }, - { "otf", ContentType.Otf }, - { "otg", ContentType.Otg }, - { "oth", ContentType.Oth }, - { "oti", ContentType.Oti }, - { "otp", ContentType.Otp }, - { "ots", ContentType.Ots }, - { "ott", ContentType.Ott }, - { "ova", ContentType.Ova }, - { "ovf", ContentType.Ovf }, - { "owl", ContentType.Owl }, - { "oxps", ContentType.Oxps }, - { "oxt", ContentType.Oxt }, - { "p", ContentType.P }, - { "p10", ContentType.P10 }, - { "p12", ContentType.P12 }, - { "p7b", ContentType.P7b }, - { "p7c", ContentType.P7c }, - { "p7m", ContentType.P7m }, - { "p7r", ContentType.P7r }, - { "p7s", ContentType.P7s }, - { "p8", ContentType.P8 }, - { "pac", ContentType.Pac }, - { "pages", ContentType.Pages }, - { "pas", ContentType.Pas }, - { "paw", ContentType.Paw }, - { "pbd", ContentType.Pbd }, - { "pbm", ContentType.Pbm }, - { "pcap", ContentType.Pcap }, - { "pcf", ContentType.Pcf }, - { "pcl", ContentType.Pcl }, - { "pclxl", ContentType.Pclxl }, - { "pct", ContentType.Pct }, - { "pcurl", ContentType.Pcurl }, - { "pcx", ContentType.Pcx }, - { "pdb", ContentType.Pdb }, - { "pde", ContentType.Pde }, - { "pdf", ContentType.Pdf }, - { "pem", ContentType.Pem }, - { "pfa", ContentType.Pfa }, - { "pfb", ContentType.Pfb }, - { "pfm", ContentType.Pfm }, - { "pfr", ContentType.Pfr }, - { "pfx", ContentType.Pfx }, - { "pgm", ContentType.Pgm }, - { "pgn", ContentType.Pgn }, - { "pgp", ContentType.Pgp }, - { "php", ContentType.Php }, - { "pic", ContentType.Pic }, - { "pkg", ContentType.Pkg }, - { "pki", ContentType.Pki }, - { "pkipath", ContentType.Pkipath }, - { "pkpass", ContentType.Pkpass }, - { "pl", ContentType.Pl }, - { "plb", ContentType.Plb }, - { "plc", ContentType.Plc }, - { "plf", ContentType.Plf }, - { "pls", ContentType.Pls }, - { "pm", ContentType.Pm }, - { "pml", ContentType.Pml }, - { "png", ContentType.Png }, - { "pnm", ContentType.Pnm }, - { "portpkg", ContentType.Portpkg }, - { "pot", ContentType.Pot }, - { "potm", ContentType.Potm }, - { "potx", ContentType.Potx }, - { "ppam", ContentType.Ppam }, - { "ppd", ContentType.Ppd }, - { "ppm", ContentType.Ppm }, - { "pps", ContentType.Pps }, - { "ppsm", ContentType.Ppsm }, - { "ppsx", ContentType.Ppsx }, - { "ppt", ContentType.Ppt }, - { "pptm", ContentType.Pptm }, - { "pptx", ContentType.Pptx }, - { "pqa", ContentType.Pqa }, - { "prc", ContentType.Prc }, - { "pre", ContentType.Pre }, - { "prf", ContentType.Prf }, - { "provx", ContentType.Provx }, - { "ps", ContentType.Ps }, - { "psb", ContentType.Psb }, - { "psd", ContentType.Psd }, - { "psf", ContentType.Psf }, - { "pskcxml", ContentType.Pskcxml }, - { "pti", ContentType.Pti }, - { "ptid", ContentType.Ptid }, - { "pub", ContentType.Pub }, - { "pvb", ContentType.Pvb }, - { "pwn", ContentType.Pwn }, - { "pya", ContentType.Pya }, - { "pyv", ContentType.Pyv }, - { "qam", ContentType.Qam }, - { "qbo", ContentType.Qbo }, - { "qfx", ContentType.Qfx }, - { "qps", ContentType.Qps }, - { "qt", ContentType.Qt }, - { "qwd", ContentType.Qwd }, - { "qwt", ContentType.Qwt }, - { "qxb", ContentType.Qxb }, - { "qxd", ContentType.Qxd }, - { "qxl", ContentType.Qxl }, - { "qxt", ContentType.Qxt }, - { "ra", ContentType.Ra }, - { "ram", ContentType.Ram }, - { "raml", ContentType.Raml }, - { "rapd", ContentType.Rapd }, - { "rar", ContentType.Rar }, - { "ras", ContentType.Ras }, - { "rdf", ContentType.Rdf }, - { "rdz", ContentType.Rdz }, - { "relo", ContentType.Relo }, - { "rep", ContentType.Rep }, - { "res", ContentType.Res }, - { "rgb", ContentType.Rgb }, - { "rif", ContentType.Rif }, - { "rip", ContentType.Rip }, - { "ris", ContentType.Ris }, - { "rl", ContentType.Rl }, - { "rlc", ContentType.Rlc }, - { "rld", ContentType.Rld }, - { "rm", ContentType.Rm }, - { "rmi", ContentType.Rmi }, - { "rmp", ContentType.Rmp }, - { "rms", ContentType.Rms }, - { "rmvb", ContentType.Rmvb }, - { "rnc", ContentType.Rnc }, - { "rng", ContentType.Rng }, - { "roa", ContentType.Roa }, - { "roff", ContentType.Roff }, - { "rp9", ContentType.Rp9 }, - { "rpm", ContentType.Rpm }, - { "rpss", ContentType.Rpss }, - { "rpst", ContentType.Rpst }, - { "rq", ContentType.Rq }, - { "rs", ContentType.Rs }, - { "rsat", ContentType.Rsat }, - { "rsd", ContentType.Rsd }, - { "rsheet", ContentType.Rsheet }, - { "rss", ContentType.Rss }, - { "rtf", ContentType.Rtf }, - { "rtx", ContentType.Rtx }, - { "run", ContentType.Run }, - { "rusd", ContentType.Rusd }, - { "s", ContentType.S }, - { "s3m", ContentType.S3m }, - { "saf", ContentType.Saf }, - { "sass", ContentType.Sass }, - { "sbml", ContentType.Sbml }, - { "sc", ContentType.Sc }, - { "scd", ContentType.Scd }, - { "scm", ContentType.Scm }, - { "scq", ContentType.Scq }, - { "scs", ContentType.Scs }, - { "scss", ContentType.Scss }, - { "scurl", ContentType.Scurl }, - { "sda", ContentType.Sda }, - { "sdc", ContentType.Sdc }, - { "sdd", ContentType.Sdd }, - { "sdkd", ContentType.Sdkd }, - { "sdkm", ContentType.Sdkm }, - { "sdp", ContentType.Sdp }, - { "sdw", ContentType.Sdw }, - { "sea", ContentType.Sea }, - { "see", ContentType.See }, - { "seed", ContentType.Seed }, - { "sema", ContentType.Sema }, - { "semd", ContentType.Semd }, - { "semf", ContentType.Semf }, - { "senmlx", ContentType.Senmlx }, - { "sensmlx", ContentType.Sensmlx }, - { "ser", ContentType.Ser }, - { "setpay", ContentType.Setpay }, - { "setreg", ContentType.Setreg }, - { "sfs", ContentType.Sfs }, - { "sfv", ContentType.Sfv }, - { "sgi", ContentType.Sgi }, - { "sgl", ContentType.Sgl }, - { "sgm", ContentType.Sgm }, - { "sgml", ContentType.Sgml }, - { "sh", ContentType.Sh }, - { "shar", ContentType.Shar }, - { "shex", ContentType.Shex }, - { "shf", ContentType.Shf }, - { "shtml", ContentType.Shtml }, - { "sid", ContentType.Sid }, - { "sieve", ContentType.Sieve }, - { "sig", ContentType.Sig }, - { "sil", ContentType.Sil }, - { "silo", ContentType.Silo }, - { "sis", ContentType.Sis }, - { "sisx", ContentType.Sisx }, - { "sit", ContentType.Sit }, - { "sitx", ContentType.Sitx }, - { "siv", ContentType.Siv }, - { "skd", ContentType.Skd }, - { "skm", ContentType.Skm }, - { "skp", ContentType.Skp }, - { "skt", ContentType.Skt }, - { "sldm", ContentType.Sldm }, - { "sldx", ContentType.Sldx }, - { "slim", ContentType.Slim }, - { "slm", ContentType.Slm }, - { "sls", ContentType.Sls }, - { "slt", ContentType.Slt }, - { "sm", ContentType.Sm }, - { "smf", ContentType.Smf }, - { "smi", ContentType.Smi }, - { "smil", ContentType.Smil }, - { "smv", ContentType.Smv }, - { "smzip", ContentType.Smzip }, - { "snd", ContentType.Snd }, - { "snf", ContentType.Snf }, - { "so", ContentType.So }, - { "spc", ContentType.Spc }, - { "spdx", ContentType.Spdx }, - { "spf", ContentType.Spf }, - { "spl", ContentType.Spl }, - { "spot", ContentType.Spot }, - { "spp", ContentType.Spp }, - { "spq", ContentType.Spq }, - { "spx", ContentType.Spx }, - { "sql", ContentType.Sql }, - { "src", ContentType.Src }, - { "srt", ContentType.Srt }, - { "sru", ContentType.Sru }, - { "srx", ContentType.Srx }, - { "ssdl", ContentType.Ssdl }, - { "sse", ContentType.Sse }, - { "ssf", ContentType.Ssf }, - { "ssml", ContentType.Ssml }, - { "st", ContentType.St }, - { "stc", ContentType.Stc }, - { "std", ContentType.Std }, - { "stf", ContentType.Stf }, - { "sti", ContentType.Sti }, - { "stk", ContentType.Stk }, - { "stl", ContentType.Stl }, - { "stpx", ContentType.Stpx }, - { "stpxz", ContentType.Stpxz }, - { "stpz", ContentType.Stpz }, - { "str", ContentType.Str }, - { "stw", ContentType.Stw }, - { "styl", ContentType.Styl }, - { "stylus", ContentType.Stylus }, - { "sub", ContentType.Sub }, - { "sus", ContentType.Sus }, - { "susp", ContentType.Susp }, - { "sv4cpio", ContentType.Sv4cpio }, - { "sv4crc", ContentType.Sv4crc }, - { "svc", ContentType.Svc }, - { "svd", ContentType.Svd }, - { "svg", ContentType.Svg }, - { "svgz", ContentType.Svgz }, - { "swa", ContentType.Swa }, - { "swf", ContentType.Swf }, - { "swi", ContentType.Swi }, - { "swidtag", ContentType.Swidtag }, - { "sxc", ContentType.Sxc }, - { "sxd", ContentType.Sxd }, - { "sxg", ContentType.Sxg }, - { "sxi", ContentType.Sxi }, - { "sxm", ContentType.Sxm }, - { "sxw", ContentType.Sxw }, - { "t", ContentType.T }, - { "t3", ContentType.T3 }, - { "t38", ContentType.T38 }, - { "taglet", ContentType.Taglet }, - { "tao", ContentType.Tao }, - { "tap", ContentType.Tap }, - { "tar", ContentType.Tar }, - { "tcap", ContentType.Tcap }, - { "tcl", ContentType.Tcl }, - { "td", ContentType.Td }, - { "teacher", ContentType.Teacher }, - { "tei", ContentType.Tei }, - { "tex", ContentType.Tex }, - { "texi", ContentType.Texi }, - { "texinfo", ContentType.Texinfo }, - { "text", ContentType.Text }, - { "tfi", ContentType.Tfi }, - { "tfm", ContentType.Tfm }, - { "tfx", ContentType.Tfx }, - { "tga", ContentType.Tga }, - { "thmx", ContentType.Thmx }, - { "tif", ContentType.Tif }, - { "tiff", ContentType.Tiff }, - { "tk", ContentType.Tk }, - { "tmo", ContentType.Tmo }, - { "toml", ContentType.Toml }, - { "torrent", ContentType.Torrent }, - { "tpl", ContentType.Tpl }, - { "tpt", ContentType.Tpt }, - { "tr", ContentType.Tr }, - { "tra", ContentType.Tra }, - { "trig", ContentType.Trig }, - { "trm", ContentType.Trm }, - { "ts", ContentType.Ts }, - { "tsd", ContentType.Tsd }, - { "tsv", ContentType.Tsv }, - { "ttc", ContentType.Ttc }, - { "ttf", ContentType.Ttf }, - { "ttl", ContentType.Ttl }, - { "ttml", ContentType.Ttml }, - { "twd", ContentType.Twd }, - { "twds", ContentType.Twds }, - { "txd", ContentType.Txd }, - { "txf", ContentType.Txf }, - { "txt", ContentType.Txt }, - { "u32", ContentType.U32 }, - { "u8dsn", ContentType.U8dsn }, - { "u8hdr", ContentType.U8hdr }, - { "u8mdn", ContentType.U8mdn }, - { "u8msg", ContentType.U8msg }, - { "ubj", ContentType.Ubj }, - { "udeb", ContentType.Udeb }, - { "ufd", ContentType.Ufd }, - { "ufdl", ContentType.Ufdl }, - { "ulx", ContentType.Ulx }, - { "umj", ContentType.Umj }, - { "unityweb", ContentType.Unityweb }, - { "uoml", ContentType.Uoml }, - { "uri", ContentType.Uri }, - { "uris", ContentType.Uris }, - { "urls", ContentType.Urls }, - { "usdz", ContentType.Usdz }, - { "ustar", ContentType.Ustar }, - { "utz", ContentType.Utz }, - { "uu", ContentType.Uu }, - { "uva", ContentType.Uva }, - { "uvd", ContentType.Uvd }, - { "uvf", ContentType.Uvf }, - { "uvg", ContentType.Uvg }, - { "uvh", ContentType.Uvh }, - { "uvi", ContentType.Uvi }, - { "uvm", ContentType.Uvm }, - { "uvp", ContentType.Uvp }, - { "uvs", ContentType.Uvs }, - { "uvt", ContentType.Uvt }, - { "uvu", ContentType.Uvu }, - { "uvv", ContentType.Uvv }, - { "uvva", ContentType.Uvva }, - { "uvvd", ContentType.Uvvd }, - { "uvvf", ContentType.Uvvf }, - { "uvvg", ContentType.Uvvg }, - { "uvvh", ContentType.Uvvh }, - { "uvvi", ContentType.Uvvi }, - { "uvvm", ContentType.Uvvm }, - { "uvvp", ContentType.Uvvp }, - { "uvvs", ContentType.Uvvs }, - { "uvvt", ContentType.Uvvt }, - { "uvvu", ContentType.Uvvu }, - { "uvvv", ContentType.Uvvv }, - { "uvvx", ContentType.Uvvx }, - { "uvvz", ContentType.Uvvz }, - { "uvx", ContentType.Uvx }, - { "uvz", ContentType.Uvz }, - { "vbox", ContentType.Vbox }, - { "vcard", ContentType.Vcard }, - { "vcd", ContentType.Vcd }, - { "vcf", ContentType.Vcf }, - { "vcg", ContentType.Vcg }, - { "vcs", ContentType.Vcs }, - { "vcx", ContentType.Vcx }, - { "vdi", ContentType.Vdi }, - { "vds", ContentType.Vds }, - { "vhd", ContentType.Vhd }, - { "vis", ContentType.Vis }, - { "viv", ContentType.Viv }, - { "vmdk", ContentType.Vmdk }, - { "vob", ContentType.Vob }, - { "vor", ContentType.Vor }, - { "vox", ContentType.Vox }, - { "vrml", ContentType.Vrml }, - { "vsd", ContentType.Vsd }, - { "vsf", ContentType.Vsf }, - { "vss", ContentType.Vss }, - { "vst", ContentType.Vst }, - { "vsw", ContentType.Vsw }, - { "vtf", ContentType.Vtf }, - { "vtt", ContentType.Vtt }, - { "vtu", ContentType.Vtu }, - { "vxml", ContentType.Vxml }, - { "w3d", ContentType.W3d }, - { "wad", ContentType.Wad }, - { "wadl", ContentType.Wadl }, - { "war", ContentType.War }, - { "wasm", ContentType.Wasm }, - { "wav", ContentType.Wav }, - { "wax", ContentType.Wax }, - { "wbmp", ContentType.Wbmp }, - { "wbs", ContentType.Wbs }, - { "wbxml", ContentType.Wbxml }, - { "wcm", ContentType.Wcm }, - { "wdb", ContentType.Wdb }, - { "wdp", ContentType.Wdp }, - { "weba", ContentType.Weba }, - { "webapp", ContentType.Webapp }, - { "webm", ContentType.Webm }, - { "webp", ContentType.Webp }, - { "wg", ContentType.Wg }, - { "wgt", ContentType.Wgt }, - { "wks", ContentType.Wks }, - { "wm", ContentType.Wm }, - { "wma", ContentType.Wma }, - { "wmd", ContentType.Wmd }, - { "wmf", ContentType.Wmf }, - { "wml", ContentType.Wml }, - { "wmlc", ContentType.Wmlc }, - { "wmls", ContentType.Wmls }, - { "wmlsc", ContentType.Wmlsc }, - { "wmv", ContentType.Wmv }, - { "wmx", ContentType.Wmx }, - { "wmz", ContentType.Wmz }, - { "woff", ContentType.Woff }, - { "woff2", ContentType.Woff2 }, - { "wpd", ContentType.Wpd }, - { "wpl", ContentType.Wpl }, - { "wps", ContentType.Wps }, - { "wqd", ContentType.Wqd }, - { "wri", ContentType.Wri }, - { "wrl", ContentType.Wrl }, - { "wsc", ContentType.Wsc }, - { "wsdl", ContentType.Wsdl }, - { "wspolicy", ContentType.Wspolicy }, - { "wtb", ContentType.Wtb }, - { "wvx", ContentType.Wvx }, - { "x32", ContentType.X32 }, - { "x3d", ContentType.X3d }, - { "x3db", ContentType.X3db }, - { "x3dbz", ContentType.X3dbz }, - { "x3dv", ContentType.X3dv }, - { "x3dvz", ContentType.X3dvz }, - { "x3dz", ContentType.X3dz }, - { "xaml", ContentType.Xaml }, - { "xap", ContentType.Xap }, - { "xar", ContentType.Xar }, - { "xav", ContentType.Xav }, - { "xbap", ContentType.Xbap }, - { "xbd", ContentType.Xbd }, - { "xbm", ContentType.Xbm }, - { "xca", ContentType.Xca }, - { "xcs", ContentType.Xcs }, - { "xdf", ContentType.Xdf }, - { "xdm", ContentType.Xdm }, - { "xdp", ContentType.Xdp }, - { "xdssc", ContentType.Xdssc }, - { "xdw", ContentType.Xdw }, - { "xel", ContentType.Xel }, - { "xenc", ContentType.Xenc }, - { "xer", ContentType.Xer }, - { "xfdf", ContentType.Xfdf }, - { "xfdl", ContentType.Xfdl }, - { "xht", ContentType.Xht }, - { "xhtml", ContentType.Xhtml }, - { "xhvml", ContentType.Xhvml }, - { "xif", ContentType.Xif }, - { "xla", ContentType.Xla }, - { "xlam", ContentType.Xlam }, - { "xlc", ContentType.Xlc }, - { "xlf", ContentType.Xlf }, - { "xlm", ContentType.Xlm }, - { "xls", ContentType.Xls }, - { "xlsb", ContentType.Xlsb }, - { "xlsm", ContentType.Xlsm }, - { "xlsx", ContentType.Xlsx }, - { "xlt", ContentType.Xlt }, - { "xltm", ContentType.Xltm }, - { "xltx", ContentType.Xltx }, - { "xlw", ContentType.Xlw }, - { "xm", ContentType.Xm }, - { "xml", ContentType.Xml }, - { "xns", ContentType.Xns }, - { "xo", ContentType.Xo }, - { "xop", ContentType.Xop }, - { "xpi", ContentType.Xpi }, - { "xpl", ContentType.Xpl }, - { "xpm", ContentType.Xpm }, - { "xpr", ContentType.Xpr }, - { "xps", ContentType.Xps }, - { "xpw", ContentType.Xpw }, - { "xpx", ContentType.Xpx }, - { "xsd", ContentType.Xsd }, - { "xsl", ContentType.Xsl }, - { "xslt", ContentType.Xslt }, - { "xsm", ContentType.Xsm }, - { "xspf", ContentType.Xspf }, - { "xul", ContentType.Xul }, - { "xvm", ContentType.Xvm }, - { "xvml", ContentType.Xvml }, - { "xwd", ContentType.Xwd }, - { "xyz", ContentType.Xyz }, - { "xz", ContentType.Xz }, - { "yaml", ContentType.Yaml }, - { "yang", ContentType.Yang }, - { "yin", ContentType.Yin }, - { "yml", ContentType.Yml }, - { "ymp", ContentType.Ymp }, - { "z1", ContentType.Z1 }, - { "z2", ContentType.Z2 }, - { "z3", ContentType.Z3 }, - { "z4", ContentType.Z4 }, - { "z5", ContentType.Z5 }, - { "z6", ContentType.Z6 }, - { "z7", ContentType.Z7 }, - { "z8", ContentType.Z8 }, - { "zaz", ContentType.Zaz }, - { "zip", ContentType.Zip }, - { "zir", ContentType.Zir }, - { "zirz", ContentType.Zirz }, - { "zmm", ContentType.Zmm }, - }; - private static readonly IReadOnlyDictionary<string, ContentType> MimeToCt = new Dictionary<string, ContentType>() - { - { "application/x-www-form-urlencoded", ContentType.UrlEncoded }, - { "multipart/form-data", ContentType.MultiPart }, - { "audio/x-aac", ContentType.Aac }, - { "application/x-authorware-map", ContentType.Aam }, - { "application/x-authorware-seg", ContentType.Aas }, - { "application/x-abiword", ContentType.Abw }, - { "application/pkix-attr-cert", ContentType.Ac }, - { "application/vnd.americandynamics.acc", ContentType.Acc }, - { "application/x-ace-compressed", ContentType.Ace }, - { "application/vnd.acucobol", ContentType.Acu }, - { "application/vnd.acucorp", ContentType.Acutc }, - { "audio/adpcm", ContentType.Adp }, - { "application/vnd.audiograph", ContentType.Aep }, - { "application/vnd.ibm.modcap", ContentType.Afp }, - { "application/vnd.ahead.space", ContentType.Ahead }, - { "audio/x-aiff", ContentType.Aiff }, - { "application/vnd.adobe.air-application-installer-package+zip", ContentType.Air }, - { "application/vnd.dvb.ait", ContentType.Ait }, - { "application/vnd.amiga.ami", ContentType.Ami }, - { "audio/amr", ContentType.Amr }, - { "application/vnd.android.package-archive", ContentType.Apk }, - { "image/apng", ContentType.Apng }, - { "application/vnd.lotus-approach", ContentType.Apr }, - { "application/x-freearc", ContentType.Arc }, - { "application/x-arj", ContentType.Arj }, - { "video/x-ms-asf", ContentType.Asf }, - { "text/x-asm", ContentType.Asm }, - { "application/vnd.accpac.simply.aso", ContentType.Aso }, - { "application/atom+xml", ContentType.Atom }, - { "application/atomcat+xml", ContentType.Atomcat }, - { "application/atomsvc+xml", ContentType.Atomsvc }, - { "application/vnd.antix.game-component", ContentType.Atx }, - { "audio/basic", ContentType.Au }, - { "video/x-msvideo", ContentType.Avi }, - { "image/avif", ContentType.Avif }, - { "application/applixware", ContentType.Aw }, - { "application/vnd.airzip.filesecure.azf", ContentType.Azf }, - { "application/vnd.airzip.filesecure.azs", ContentType.Azs }, - { "image/vnd.airzip.accelerator.azv", ContentType.Azv }, - { "application/vnd.amazon.ebook", ContentType.Azw }, - { "image/vnd.pco.b16", ContentType.B16 }, - { "application/x-msdownload", ContentType.Bat }, - { "application/x-bcpio", ContentType.Bcpio }, - { "application/x-font-bdf", ContentType.Bdf }, - { "application/vnd.syncml.dm+wbxml", ContentType.Bdm }, - { "application/bdoc", ContentType.Bdoc }, - { "application/vnd.realvnc.bed", ContentType.Bed }, - { "application/vnd.fujitsu.oasysprs", ContentType.Bh2 }, - { "application/octet-stream", ContentType.Binary }, - { "application/x-blorb", ContentType.Blorb }, - { "application/vnd.bmi", ContentType.Bmi }, - { "application/vnd.balsamiq.bmml+xml", ContentType.Bmml }, - { "image/bmp", ContentType.Bmp }, - { "application/vnd.previewsystems.box", ContentType.Box }, - { "application/x-bzip2", ContentType.Boz }, - { "model/vnd.valve.source.compiled-map", ContentType.Bsp }, - { "image/prs.btif", ContentType.Btif }, - { "application/x-bzip", ContentType.Bz }, - { "text/x-c", ContentType.C }, - { "application/vnd.cluetrust.cartomobile-config", ContentType.C11amc }, - { "application/vnd.cluetrust.cartomobile-config-pkg", ContentType.C11amz }, - { "application/vnd.clonk.c4group", ContentType.C4d }, - { "application/vnd.ms-cab-compressed", ContentType.Cab }, - { "audio/x-caf", ContentType.Caf }, - { "application/vnd.curl.car", ContentType.Car }, - { "application/vnd.ms-pki.seccat", ContentType.Cat }, - { "application/x-cbr", ContentType.Cb7 }, - { "application/x-cocoa", ContentType.Cco }, - { "application/ccxml+xml", ContentType.Ccxml }, - { "application/vnd.contact.cmsg", ContentType.Cdbcmsg }, - { "application/x-netcdf", ContentType.Cdf }, - { "application/cdfx+xml", ContentType.Cdfx }, - { "application/vnd.mediastation.cdkey", ContentType.Cdkey }, - { "application/cdmi-capability", ContentType.Cdmia }, - { "application/cdmi-container", ContentType.Cdmic }, - { "application/cdmi-domain", ContentType.Cdmid }, - { "application/cdmi-object", ContentType.Cdmio }, - { "application/cdmi-queue", ContentType.Cdmiq }, - { "chemical/x-cdx", ContentType.Cdx }, - { "application/vnd.chemdraw+xml", ContentType.Cdxml }, - { "application/vnd.cinderella", ContentType.Cdy }, - { "application/pkix-cert", ContentType.Cer }, - { "application/x-cfs-compressed", ContentType.Cfs }, - { "image/cgm", ContentType.Cgm }, - { "application/x-chat", ContentType.Chat }, - { "application/vnd.ms-htmlhelp", ContentType.Chm }, - { "application/vnd.kde.kchart", ContentType.Chrt }, - { "chemical/x-cif", ContentType.Cif }, - { "application/vnd.anser-web-certificate-issue-initiation", ContentType.Cii }, - { "application/vnd.ms-artgalry", ContentType.Cil }, - { "application/node", ContentType.Cjs }, - { "application/vnd.claymore", ContentType.Cla }, - { "application/vnd.crick.clicker.keyboard", ContentType.Clkk }, - { "application/vnd.crick.clicker.palette", ContentType.Clkp }, - { "application/vnd.crick.clicker.template", ContentType.Clkt }, - { "application/vnd.crick.clicker.wordbank", ContentType.Clkw }, - { "application/vnd.crick.clicker", ContentType.Clkx }, - { "application/x-msclip", ContentType.Clp }, - { "application/vnd.cosmocaller", ContentType.Cmc }, - { "chemical/x-cmdf", ContentType.Cmdf }, - { "chemical/x-cml", ContentType.Cml }, - { "application/vnd.yellowriver-custom-menu", ContentType.Cmp }, - { "image/x-cmx", ContentType.Cmx }, - { "application/vnd.rim.cod", ContentType.Cod }, - { "text/coffeescript", ContentType.Coffee }, - { "application/x-cpio", ContentType.Cpio }, - { "application/mac-compactpro", ContentType.Cpt }, - { "application/x-mscardfile", ContentType.Crd }, - { "application/pkix-crl", ContentType.Crl }, - { "application/x-x509-ca-cert", ContentType.Crt }, - { "application/x-chrome-extension", ContentType.Crx }, - { "application/x-csh", ContentType.Csh }, - { "application/vnd.citationstyles.style+xml", ContentType.Csl }, - { "chemical/x-csml", ContentType.Csml }, - { "application/vnd.commonspace", ContentType.Csp }, - { "text/css", ContentType.Css }, - { "text/csv", ContentType.Csv }, - { "application/cu-seeme", ContentType.Cu }, - { "text/vnd.curl", ContentType.Curl }, - { "application/prs.cww", ContentType.Cww }, - { "model/vnd.collada+xml", ContentType.Dae }, - { "application/vnd.mobius.daf", ContentType.Daf }, - { "application/vnd.dart", ContentType.Dart }, - { "application/davmount+xml", ContentType.Davmount }, - { "application/vnd.dbf", ContentType.Dbf }, - { "application/docbook+xml", ContentType.Dbk }, - { "application/x-director", ContentType.Dcr }, - { "text/vnd.curl.dcurl", ContentType.Dcurl }, - { "application/vnd.oma.dd2+xml", ContentType.Dd2 }, - { "application/vnd.fujixerox.ddd", ContentType.Ddd }, - { "application/vnd.syncml.dmddf+xml", ContentType.Ddf }, - { "image/vnd.ms-dds", ContentType.Dds }, - { "application/vnd.dreamfactory", ContentType.Dfac }, - { "application/x-dgc-compressed", ContentType.Dgc }, - { "application/vnd.mobius.dis", ContentType.Dis }, - { "image/vnd.djvu", ContentType.Djvu }, - { "application/vnd.dna", ContentType.Dna }, - { "application/msword", ContentType.Doc }, - { "application/vnd.ms-word.document.macroenabled.12", ContentType.Docm }, - { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ContentType.Docx }, - { "application/vnd.openxmlformats-officedocument.wordprocessingml.template", ContentType.Dotx }, - { "application/vnd.osgi.dp", ContentType.Dp }, - { "application/vnd.dpgraph", ContentType.Dpg }, - { "audio/vnd.dra", ContentType.Dra }, - { "image/dicom-rle", ContentType.Drle }, - { "text/prs.lines.tag", ContentType.Dsc }, - { "application/dssc+der", ContentType.Dssc }, - { "application/x-dtbook+xml", ContentType.Dtb }, - { "application/xml-dtd", ContentType.Dtd }, - { "audio/vnd.dts", ContentType.Dts }, - { "audio/vnd.dts.hd", ContentType.Dtshd }, - { "video/vnd.dvb.file", ContentType.Dvb }, - { "application/x-dvi", ContentType.Dvi }, - { "application/atsc-dwd+xml", ContentType.Dwd }, - { "model/vnd.dwf", ContentType.Dwf }, - { "image/vnd.dwg", ContentType.Dwg }, - { "image/vnd.dxf", ContentType.Dxf }, - { "application/vnd.spotfire.dxp", ContentType.Dxp }, - { "application/ecmascript", ContentType.Ecma }, - { "application/vnd.novadigm.edm", ContentType.Edm }, - { "application/vnd.novadigm.edx", ContentType.Edx }, - { "application/vnd.picsel", ContentType.Efif }, - { "application/vnd.pg.osasli", ContentType.Ei6 }, - { "application/emma+xml", ContentType.Emma }, - { "audio/vnd.digital-winds", ContentType.Eol }, - { "application/vnd.ms-fontobject", ContentType.Eot }, - { "application/epub+zip", ContentType.Epub }, - { "application/vnd.osgi.subsystem", ContentType.Esa }, - { "application/vnd.epson.esf", ContentType.Esf }, - { "application/vnd.eszigno3+xml", ContentType.Et3 }, - { "text/x-setext", ContentType.Etx }, - { "application/x-eva", ContentType.Eva }, - { "application/x-envoy", ContentType.Evy }, - { "application/exi", ContentType.Exi }, - { "application/express", ContentType.Exp }, - { "image/aces", ContentType.Exr }, - { "application/vnd.novadigm.ext", ContentType.Ext }, - { "application/andrew-inset", ContentType.Ez }, - { "application/vnd.ezpix-album", ContentType.Ez2 }, - { "application/vnd.ezpix-package", ContentType.Ez3 }, - { "video/x-f4v", ContentType.F4v }, - { "text/x-fortran", ContentType.Fortran }, - { "image/vnd.fastbidsheet", ContentType.Fbs }, - { "application/vnd.adobe.formscentral.fcdt", ContentType.Fcdt }, - { "application/vnd.isac.fcs", ContentType.Fcs }, - { "application/vnd.fdf", ContentType.Fdf }, - { "application/fdt+xml", ContentType.Fdt }, - { "application/vnd.fujitsu.oasysgp", ContentType.Fg5 }, - { "image/x-freehand", ContentType.Fh }, - { "application/x-xfig", ContentType.Fig }, - { "image/fits", ContentType.Fits }, - { "audio/x-flac", ContentType.Flac }, - { "video/x-fli", ContentType.Fli }, - { "application/vnd.micrografx.flo", ContentType.Flo }, - { "video/x-flv", ContentType.Flv }, - { "application/vnd.kde.kivio", ContentType.Flw }, - { "text/vnd.fmi.flexstor", ContentType.Flx }, - { "text/vnd.fly", ContentType.Fly }, - { "application/vnd.frogans.fnc", ContentType.Fnc }, - { "application/vnd.software602.filler.form+xml", ContentType.Fo }, - { "image/vnd.fpx", ContentType.Fpx }, - { "application/vnd.framemaker", ContentType.Frame }, - { "application/vnd.fsc.weblaunch", ContentType.Fsc }, - { "image/vnd.fst", ContentType.Fst }, - { "application/vnd.fluxtime.clip", ContentType.Ftc }, - { "application/vnd.anser-web-funds-transfer-initiation", ContentType.Fti }, - { "video/vnd.fvt", ContentType.Fvt }, - { "application/vnd.adobe.fxp", ContentType.Fxp }, - { "application/vnd.fuzzysheet", ContentType.Fzs }, - { "application/vnd.geoplan", ContentType.G2w }, - { "image/g3fax", ContentType.G3 }, - { "application/vnd.geospace", ContentType.G3w }, - { "application/vnd.groove-account", ContentType.Gac }, - { "application/x-tads", ContentType.Gam }, - { "application/rpki-ghostbusters", ContentType.Gbr }, - { "application/x-gca-compressed", ContentType.Gca }, - { "model/vnd.gdl", ContentType.Gdl }, - { "application/vnd.google-apps.document", ContentType.Gdoc }, - { "application/vnd.dynageo", ContentType.Geo }, - { "application/geo+json", ContentType.Geojson }, - { "application/vnd.geometry-explorer", ContentType.Gex }, - { "application/vnd.geogebra.file", ContentType.Ggb }, - { "application/vnd.geogebra.tool", ContentType.Ggt }, - { "application/vnd.groove-help", ContentType.Ghf }, - { "image/gif", ContentType.Gif }, - { "application/vnd.groove-identity-message", ContentType.Gim }, - { "model/gltf-binary", ContentType.Glb }, - { "model/gltf+json", ContentType.Gltf }, - { "application/gml+xml", ContentType.Gml }, - { "application/vnd.gmx", ContentType.Gmx }, - { "application/x-gnumeric", ContentType.Gnumeric }, - { "application/vnd.flographit", ContentType.Gph }, - { "application/gpx+xml", ContentType.Gpx }, - { "application/vnd.grafeq", ContentType.Gqf }, - { "application/srgs", ContentType.Gram }, - { "application/x-gramps-xml", ContentType.Gramps }, - { "application/vnd.groove-injector", ContentType.Grv }, - { "application/srgs+xml", ContentType.Grxml }, - { "application/x-font-ghostscript", ContentType.Gsf }, - { "application/vnd.google-apps.spreadsheet", ContentType.Gsheet }, - { "application/vnd.google-apps.presentation", ContentType.Gslides }, - { "application/x-gtar", ContentType.Gtar }, - { "application/vnd.groove-tool-message", ContentType.Gtm }, - { "model/vnd.gtw", ContentType.Gtw }, - { "text/vnd.graphviz", ContentType.Gv }, - { "application/gxf", ContentType.Gxf }, - { "application/vnd.geonext", ContentType.Gxt }, - { "application/gzip", ContentType.Gz }, - { "video/h261", ContentType.H261 }, - { "video/h263", ContentType.H263 }, - { "video/h264", ContentType.H264 }, - { "application/vnd.hal+xml", ContentType.Hal }, - { "application/vnd.hbci", ContentType.Hbci }, - { "text/x-handlebars-template", ContentType.Hbs }, - { "application/x-virtualbox-hdd", ContentType.Hdd }, - { "application/x-hdf", ContentType.Hdf }, - { "image/heic", ContentType.Heic }, - { "image/heic-sequence", ContentType.Heics }, - { "image/heif", ContentType.Heif }, - { "image/heif-sequence", ContentType.Heifs }, - { "image/hej2k", ContentType.Hej2 }, - { "application/atsc-held+xml", ContentType.Held }, - { "application/hjson", ContentType.Hjson }, - { "application/winhlp", ContentType.Hlp }, - { "application/vnd.hp-hpgl", ContentType.Hpgl }, - { "application/vnd.hp-hpid", ContentType.Hpid }, - { "application/vnd.hp-hps", ContentType.Hps }, - { "application/mac-binhex40", ContentType.Hqx }, - { "image/hsj2", ContentType.Hsj2 }, - { "application/vnd.kenameaapp", ContentType.Htke }, - { "text/html", ContentType.Html }, - { "application/vnd.yamaha.hv-dic", ContentType.Hvd }, - { "application/vnd.yamaha.hv-voice", ContentType.Hvp }, - { "application/vnd.yamaha.hv-script", ContentType.Hvs }, - { "application/vnd.intergeo", ContentType.I2g }, - { "application/vnd.iccprofile", ContentType.Icc }, - { "x-conference/x-cooltalk", ContentType.Ice }, - { "image/vnd.microsoft.icon", ContentType.Ico }, - { "image/ief", ContentType.Ief }, - { "application/vnd.shana.informed.formdata", ContentType.Ifm }, - { "model/iges", ContentType.Iges }, - { "application/vnd.igloader", ContentType.Igl }, - { "application/vnd.insors.igm", ContentType.Igm }, - { "application/vnd.micrografx.igx", ContentType.Igx }, - { "application/vnd.shana.informed.interchange", ContentType.Iif }, - { "application/vnd.accpac.simply.imp", ContentType.Imp }, - { "application/vnd.ms-ims", ContentType.Ims }, - { "application/inkml+xml", ContentType.Inkml }, - { "application/x-install-instructions", ContentType.Install }, - { "application/vnd.astraea-software.iota", ContentType.Iota }, - { "application/ipfix", ContentType.Ipfix }, - { "application/vnd.shana.informed.package", ContentType.Ipk }, - { "application/vnd.ibm.rights-management", ContentType.Irm }, - { "application/vnd.irepository.package+xml", ContentType.Irp }, - { "application/vnd.shana.informed.formtemplate", ContentType.Itp }, - { "application/its+xml", ContentType.Its }, - { "application/vnd.immervision-ivp", ContentType.Ivp }, - { "application/vnd.immervision-ivu", ContentType.Ivu }, - { "text/vnd.sun.j2me.app-descriptor", ContentType.Jad }, - { "text/jade", ContentType.Jade }, - { "application/vnd.jam", ContentType.Jam }, - { "application/java-archive", ContentType.Jar }, - { "application/x-java-archive-diff", ContentType.Jardiff }, - { "text/x-java-source", ContentType.Java }, - { "image/jphc", ContentType.Jhc }, - { "application/vnd.jisp", ContentType.Jisp }, - { "image/jls", ContentType.Jls }, - { "application/vnd.hp-jlyt", ContentType.Jlt }, - { "image/x-jng", ContentType.Jng }, - { "application/x-java-jnlp-file", ContentType.Jnlp }, - { "application/vnd.joost.joda-archive", ContentType.Joda }, - { "image/jp2", ContentType.Jp2 }, - { "image/jpeg", ContentType.Jpeg }, - { "video/jpm", ContentType.Jpgm }, - { "video/jpeg", ContentType.Jpgv }, - { "image/jph", ContentType.Jph }, - { "image/jpm", ContentType.Jpm }, - { "image/jpx", ContentType.Jpx }, - { "application/javascript", ContentType.Javascript }, - { "application/json", ContentType.Json }, - { "application/json5", ContentType.Json5 }, - { "application/ld+json", ContentType.Jsonld }, - { "application/jsonml+json", ContentType.Jsonml }, - { "text/jsx", ContentType.Jsx }, - { "image/jxr", ContentType.Jxr }, - { "image/jxra", ContentType.Jxra }, - { "image/jxrs", ContentType.Jxrs }, - { "image/jxs", ContentType.Jxs }, - { "image/jxsc", ContentType.Jxsc }, - { "image/jxsi", ContentType.Jxsi }, - { "image/jxss", ContentType.Jxss }, - { "application/vnd.kde.karbon", ContentType.Karbon }, - { "application/x-keepass2", ContentType.Kdbx }, - { "application/vnd.apple.keynote", ContentType.Key }, - { "application/vnd.kde.kformula", ContentType.Kfo }, - { "application/vnd.kidspiration", ContentType.Kia }, - { "application/vnd.google-earth.kml+xml", ContentType.Kml }, - { "application/vnd.google-earth.kmz", ContentType.Kmz }, - { "application/vnd.kinar", ContentType.Kne }, - { "application/vnd.kde.kontour", ContentType.Kon }, - { "application/vnd.kde.kpresenter", ContentType.Kpr }, - { "application/vnd.ds-keypoint", ContentType.Kpxx }, - { "application/vnd.kde.kspread", ContentType.Ksp }, - { "image/ktx", ContentType.Ktx }, - { "image/ktx2", ContentType.Ktx2 }, - { "application/vnd.kahootz", ContentType.Ktz }, - { "application/vnd.kde.kword", ContentType.Kwd }, - { "application/vnd.las.las+xml", ContentType.Lasxml }, - { "application/x-latex", ContentType.Latex }, - { "application/vnd.llamagraphics.life-balance.desktop", ContentType.Lbd }, - { "application/vnd.llamagraphics.life-balance.exchange+xml", ContentType.Lbe }, - { "application/vnd.hhe.lesson-player", ContentType.Les }, - { "text/less", ContentType.Less }, - { "application/lgr+xml", ContentType.Lgr }, - { "application/vnd.route66.link66+xml", ContentType.Link66 }, - { "application/x-ms-shortcut", ContentType.Lnk }, - { "application/lost+xml", ContentType.Lostxml }, - { "application/vnd.ms-lrm", ContentType.Lrm }, - { "application/vnd.frogans.ltf", ContentType.Ltf }, - { "text/x-lua", ContentType.Lua }, - { "application/x-lua-bytecode", ContentType.Luac }, - { "audio/vnd.lucent.voice", ContentType.Lvp }, - { "application/vnd.lotus-wordpro", ContentType.Lwp }, - { "application/x-lzh-compressed", ContentType.Lzh }, - { "audio/mpeg", ContentType.M2a }, - { "audio/x-mpegurl", ContentType.M3u }, - { "application/vnd.apple.mpegurl", ContentType.M3u8 }, - { "audio/mp4", ContentType.M4a }, - { "video/iso.segment", ContentType.M4s }, - { "video/vnd.mpegurl", ContentType.M4u }, - { "video/x-m4v", ContentType.M4v }, - { "application/mathematica", ContentType.Ma }, - { "application/mads+xml", ContentType.Mads }, - { "application/mmt-aei+xml", ContentType.Maei }, - { "application/vnd.ecowin.chart", ContentType.Mag }, - { "text/cache-manifest", ContentType.Manifest }, - { "text/markdown", ContentType.Markdown }, - { "application/mathml+xml", ContentType.Mathml }, - { "application/vnd.mobius.mbk", ContentType.Mbk }, - { "application/mbox", ContentType.Mbox }, - { "application/vnd.medcalcdata", ContentType.Mc1 }, - { "application/vnd.mcd", ContentType.Mcd }, - { "text/vnd.curl.mcurl", ContentType.Mcurl }, - { "application/x-msaccess", ContentType.Mdb }, - { "image/vnd.ms-modi", ContentType.Mdi }, - { "text/mdx", ContentType.Mdx }, - { "model/mesh", ContentType.Mesh }, - { "application/metalink4+xml", ContentType.Meta4 }, - { "application/metalink+xml", ContentType.Metalink }, - { "application/mets+xml", ContentType.Mets }, - { "application/vnd.mfmp", ContentType.Mfm }, - { "application/rpki-manifest", ContentType.Mft }, - { "application/vnd.osgeo.mapguide.package", ContentType.Mgp }, - { "application/vnd.proteus.magazine", ContentType.Mgz }, - { "audio/midi", ContentType.Midi }, - { "application/x-mie", ContentType.Mie }, - { "application/vnd.mif", ContentType.Mif }, - { "message/rfc822", ContentType.Mime }, - { "video/mj2", ContentType.Mj2 }, - { "audio/x-matroska", ContentType.Mka }, - { "text/x-markdown", ContentType.Mkd }, - { "video/x-matroska", ContentType.Mkv }, - { "application/vnd.dolby.mlp", ContentType.Mlp }, - { "application/vnd.chipnuts.karaoke-mmd", ContentType.Mmd }, - { "application/vnd.smaf", ContentType.Mmf }, - { "text/mathml", ContentType.Mml }, - { "image/vnd.fujixerox.edmics-mmr", ContentType.Mmr }, - { "video/x-mng", ContentType.Mng }, - { "application/x-msmoney", ContentType.Mny }, - { "application/mods+xml", ContentType.Mods }, - { "video/x-sgi-movie", ContentType.Movie }, - { "application/mp21", ContentType.Mp21 }, - { "audio/mp3", ContentType.Mp3 }, - { "video/mp4", ContentType.Mp4 }, - { "application/mp4", ContentType.Mp4s }, - { "application/vnd.mophun.certificate", ContentType.Mpc }, - { "application/dash+xml", ContentType.Mpd }, - { "video/mpeg", ContentType.Mpeg }, - { "application/vnd.apple.installer+xml", ContentType.Mpkg }, - { "application/vnd.blueice.multipass", ContentType.Mpm }, - { "application/vnd.mophun.application", ContentType.Mpn }, - { "application/vnd.ms-project", ContentType.Mpt }, - { "application/vnd.ibm.minipay", ContentType.Mpy }, - { "application/vnd.mobius.mqy", ContentType.Mqy }, - { "application/marc", ContentType.Mrc }, - { "application/marcxml+xml", ContentType.Mrcx }, - { "application/mediaservercontrol+xml", ContentType.Mscml }, - { "application/vnd.fdsn.mseed", ContentType.Mseed }, - { "application/vnd.mseq", ContentType.Mseq }, - { "application/vnd.epson.msf", ContentType.Msf }, - { "application/vnd.ms-outlook", ContentType.Msg }, - { "application/vnd.mobius.msl", ContentType.Msl }, - { "application/vnd.muvee.style", ContentType.Msty }, - { "model/mtl", ContentType.Mtl }, - { "model/vnd.mts", ContentType.Mts }, - { "application/vnd.musician", ContentType.Mus }, - { "application/mmt-usd+xml", ContentType.Musd }, - { "application/vnd.recordare.musicxml+xml", ContentType.Musicxml }, - { "application/x-msmediaview", ContentType.Mvb }, - { "application/vnd.mapbox-vector-tile", ContentType.Mvt }, - { "application/vnd.mfer", ContentType.Mwf }, - { "application/mxf", ContentType.Mxf }, - { "application/vnd.recordare.musicxml", ContentType.Mxl }, - { "audio/mobile-xmf", ContentType.Mxmf }, - { "application/vnd.triscape.mxs", ContentType.Mxs }, - { "text/n3", ContentType.N3 }, - { "application/vnd.wolfram.player", ContentType.Nbp }, - { "application/x-dtbncx+xml", ContentType.Ncx }, - { "text/x-nfo", ContentType.Nfo }, - { "application/vnd.nokia.n-gage.data", ContentType.Ngdat }, - { "application/vnd.nitf", ContentType.Nitf }, - { "application/vnd.neurolanguage.nlu", ContentType.Nlu }, - { "application/vnd.enliven", ContentType.Nml }, - { "application/vnd.noblenet-directory", ContentType.Nnd }, - { "application/vnd.noblenet-sealer", ContentType.Nns }, - { "application/vnd.noblenet-web", ContentType.Nnw }, - { "image/vnd.net-fpx", ContentType.Npx }, - { "application/n-quads", ContentType.Nq }, - { "application/x-conference", ContentType.Nsc }, - { "application/vnd.lotus-notes", ContentType.Nsf }, - { "application/n-triples", ContentType.Nt }, - { "application/vnd.apple.numbers", ContentType.Numbers }, - { "application/x-nzb", ContentType.Nzb }, - { "application/vnd.fujitsu.oasys2", ContentType.Oa2 }, - { "application/vnd.fujitsu.oasys3", ContentType.Oa3 }, - { "application/vnd.fujitsu.oasys", ContentType.Oas }, - { "application/x-msbinder", ContentType.Obd }, - { "application/vnd.openblox.game+xml", ContentType.Obgx }, - { "application/x-tgif", ContentType.Obj }, - { "application/oda", ContentType.Oda }, - { "application/vnd.oasis.opendocument.database", ContentType.Odb }, - { "application/vnd.oasis.opendocument.chart", ContentType.Odc }, - { "application/vnd.oasis.opendocument.formula", ContentType.Odf }, - { "application/vnd.oasis.opendocument.formula-template", ContentType.Odft }, - { "application/vnd.oasis.opendocument.graphics", ContentType.Odg }, - { "application/vnd.oasis.opendocument.image", ContentType.Odi }, - { "application/vnd.oasis.opendocument.text-master", ContentType.Odm }, - { "application/vnd.oasis.opendocument.presentation", ContentType.Odp }, - { "application/vnd.oasis.opendocument.spreadsheet", ContentType.Ods }, - { "application/vnd.oasis.opendocument.text", ContentType.Odt }, - { "model/vnd.opengex", ContentType.Ogex }, - { "audio/ogg", ContentType.Ogg }, - { "video/ogg", ContentType.Ogv }, - { "application/ogg", ContentType.Ogx }, - { "application/omdoc+xml", ContentType.Omdoc }, - { "application/onenote", ContentType.Onetoc }, - { "application/oebps-package+xml", ContentType.Opf }, - { "text/x-opml", ContentType.Opml }, - { "application/vnd.lotus-organizer", ContentType.Org }, - { "application/vnd.yamaha.openscoreformat", ContentType.Osf }, - { "application/vnd.yamaha.openscoreformat.osfpvg+xml", ContentType.Osfpvg }, - { "application/vnd.openstreetmap.data+xml", ContentType.Osm }, - { "application/vnd.oasis.opendocument.chart-template", ContentType.Otc }, - { "font/otf", ContentType.Otf }, - { "application/vnd.oasis.opendocument.graphics-template", ContentType.Otg }, - { "application/vnd.oasis.opendocument.text-web", ContentType.Oth }, - { "application/vnd.oasis.opendocument.image-template", ContentType.Oti }, - { "application/vnd.oasis.opendocument.presentation-template", ContentType.Otp }, - { "application/vnd.oasis.opendocument.spreadsheet-template", ContentType.Ots }, - { "application/vnd.oasis.opendocument.text-template", ContentType.Ott }, - { "application/x-virtualbox-ova", ContentType.Ova }, - { "application/x-virtualbox-ovf", ContentType.Ovf }, - { "application/oxps", ContentType.Oxps }, - { "application/vnd.openofficeorg.extension", ContentType.Oxt }, - { "text/x-pascal", ContentType.P }, - { "application/pkcs10", ContentType.P10 }, - { "application/x-pkcs7-certificates", ContentType.P7b }, - { "application/pkcs7-mime", ContentType.P7m }, - { "application/x-pkcs7-certreqresp", ContentType.P7r }, - { "application/pkcs7-signature", ContentType.P7s }, - { "application/pkcs8", ContentType.P8 }, - { "application/x-ns-proxy-autoconfig", ContentType.Pac }, - { "application/vnd.apple.pages", ContentType.Pages }, - { "application/vnd.pawaafile", ContentType.Paw }, - { "application/vnd.powerbuilder6", ContentType.Pbd }, - { "image/x-portable-bitmap", ContentType.Pbm }, - { "application/vnd.tcpdump.pcap", ContentType.Pcap }, - { "application/x-font-pcf", ContentType.Pcf }, - { "application/vnd.hp-pcl", ContentType.Pcl }, - { "application/vnd.hp-pclxl", ContentType.Pclxl }, - { "image/x-pict", ContentType.Pct }, - { "application/vnd.curl.pcurl", ContentType.Pcurl }, - { "image/vnd.zbrush.pcx", ContentType.Pcx }, - { "application/vnd.palm", ContentType.Pdb }, - { "text/x-processing", ContentType.Pde }, - { "application/pdf", ContentType.Pdf }, - { "application/x-font-type1", ContentType.Pfa }, - { "application/font-tdpfr", ContentType.Pfr }, - { "application/x-pkcs12", ContentType.Pfx }, - { "image/x-portable-graymap", ContentType.Pgm }, - { "application/x-chess-pgn", ContentType.Pgn }, - { "application/pgp-encrypted", ContentType.Pgp }, - { "application/x-httpd-php", ContentType.Php }, - { "application/pkixcmp", ContentType.Pki }, - { "application/pkix-pkipath", ContentType.Pkipath }, - { "application/vnd.apple.pkpass", ContentType.Pkpass }, - { "application/x-perl", ContentType.Pl }, - { "application/vnd.3gpp.pic-bw-large", ContentType.Plb }, - { "application/vnd.mobius.plc", ContentType.Plc }, - { "application/vnd.pocketlearn", ContentType.Plf }, - { "application/pls+xml", ContentType.Pls }, - { "application/vnd.ctc-posml", ContentType.Pml }, - { "image/png", ContentType.Png }, - { "image/x-portable-anymap", ContentType.Pnm }, - { "application/vnd.macports.portpkg", ContentType.Portpkg }, - { "application/vnd.ms-powerpoint.template.macroenabled.12", ContentType.Potm }, - { "application/vnd.openxmlformats-officedocument.presentationml.template", ContentType.Potx }, - { "application/vnd.ms-powerpoint.addin.macroenabled.12", ContentType.Ppam }, - { "application/vnd.cups-ppd", ContentType.Ppd }, - { "image/x-portable-pixmap", ContentType.Ppm }, - { "application/vnd.ms-powerpoint.slideshow.macroenabled.12", ContentType.Ppsm }, - { "application/vnd.openxmlformats-officedocument.presentationml.slideshow", ContentType.Ppsx }, - { "application/vnd.ms-powerpoint", ContentType.Ppt }, - { "application/vnd.ms-powerpoint.presentation.macroenabled.12", ContentType.Pptm }, - { "application/vnd.openxmlformats-officedocument.presentationml.presentation", ContentType.Pptx }, - { "application/x-mobipocket-ebook", ContentType.Prc }, - { "application/vnd.lotus-freelance", ContentType.Pre }, - { "application/pics-rules", ContentType.Prf }, - { "application/provenance+xml", ContentType.Provx }, - { "application/postscript", ContentType.Ps }, - { "application/vnd.3gpp.pic-bw-small", ContentType.Psb }, - { "image/vnd.adobe.photoshop", ContentType.Psd }, - { "application/x-font-linux-psf", ContentType.Psf }, - { "application/pskc+xml", ContentType.Pskcxml }, - { "image/prs.pti", ContentType.Pti }, - { "application/vnd.pvi.ptid1", ContentType.Ptid }, - { "application/x-mspublisher", ContentType.Pub }, - { "application/vnd.3gpp.pic-bw-var", ContentType.Pvb }, - { "application/vnd.3m.post-it-notes", ContentType.Pwn }, - { "audio/vnd.ms-playready.media.pya", ContentType.Pya }, - { "video/vnd.ms-playready.media.pyv", ContentType.Pyv }, - { "application/vnd.epson.quickanime", ContentType.Qam }, - { "application/vnd.intu.qbo", ContentType.Qbo }, - { "application/vnd.intu.qfx", ContentType.Qfx }, - { "application/vnd.publishare-delta-tree", ContentType.Qps }, - { "video/quicktime", ContentType.Qt }, - { "application/vnd.quark.quarkxpress", ContentType.Qwd }, - { "audio/x-pn-realaudio", ContentType.Ra }, - { "application/raml+yaml", ContentType.Raml }, - { "application/route-apd+xml", ContentType.Rapd }, - { "application/vnd.rar", ContentType.Rar }, - { "image/x-cmu-raster", ContentType.Ras }, - { "application/rdf+xml", ContentType.Rdf }, - { "application/vnd.data-vision.rdz", ContentType.Rdz }, - { "application/p2p-overlay+xml", ContentType.Relo }, - { "application/vnd.businessobjects", ContentType.Rep }, - { "application/x-dtbresource+xml", ContentType.Res }, - { "image/x-rgb", ContentType.Rgb }, - { "application/reginfo+xml", ContentType.Rif }, - { "audio/vnd.rip", ContentType.Rip }, - { "application/x-research-info-systems", ContentType.Ris }, - { "application/resource-lists+xml", ContentType.Rl }, - { "image/vnd.fujixerox.edmics-rlc", ContentType.Rlc }, - { "application/resource-lists-diff+xml", ContentType.Rld }, - { "application/vnd.rn-realmedia", ContentType.Rm }, - { "audio/x-pn-realaudio-plugin", ContentType.Rmp }, - { "application/vnd.jcp.javame.midlet-rms", ContentType.Rms }, - { "application/vnd.rn-realmedia-vbr", ContentType.Rmvb }, - { "application/relax-ng-compact-syntax", ContentType.Rnc }, - { "application/rpki-roa", ContentType.Roa }, - { "text/troff", ContentType.Roff }, - { "application/vnd.cloanto.rp9", ContentType.Rp9 }, - { "application/x-redhat-package-manager", ContentType.Rpm }, - { "application/vnd.nokia.radio-presets", ContentType.Rpss }, - { "application/vnd.nokia.radio-preset", ContentType.Rpst }, - { "application/sparql-query", ContentType.Rq }, - { "application/rls-services+xml", ContentType.Rs }, - { "application/atsc-rsat+xml", ContentType.Rsat }, - { "application/rsd+xml", ContentType.Rsd }, - { "application/urc-ressheet+xml", ContentType.Rsheet }, - { "application/rss+xml", ContentType.Rss }, - { "application/rtf", ContentType.Rtf }, - { "text/richtext", ContentType.Rtx }, - { "application/x-makeself", ContentType.Run }, - { "application/route-usd+xml", ContentType.Rusd }, - { "audio/s3m", ContentType.S3m }, - { "application/vnd.yamaha.smaf-audio", ContentType.Saf }, - { "text/x-sass", ContentType.Sass }, - { "application/sbml+xml", ContentType.Sbml }, - { "application/vnd.ibm.secure-container", ContentType.Sc }, - { "application/x-msschedule", ContentType.Scd }, - { "application/vnd.lotus-screencam", ContentType.Scm }, - { "application/scvp-cv-request", ContentType.Scq }, - { "application/scvp-cv-response", ContentType.Scs }, - { "text/x-scss", ContentType.Scss }, - { "text/vnd.curl.scurl", ContentType.Scurl }, - { "application/vnd.stardivision.draw", ContentType.Sda }, - { "application/vnd.stardivision.calc", ContentType.Sdc }, - { "application/vnd.stardivision.impress", ContentType.Sdd }, - { "application/vnd.solent.sdkm+xml", ContentType.Sdkm }, - { "application/sdp", ContentType.Sdp }, - { "application/vnd.stardivision.writer", ContentType.Sdw }, - { "application/x-sea", ContentType.Sea }, - { "application/vnd.seemail", ContentType.See }, - { "application/vnd.fdsn.seed", ContentType.Seed }, - { "application/vnd.sema", ContentType.Sema }, - { "application/vnd.semd", ContentType.Semd }, - { "application/vnd.semf", ContentType.Semf }, - { "application/senml+xml", ContentType.Senmlx }, - { "application/sensml+xml", ContentType.Sensmlx }, - { "application/java-serialized-object", ContentType.Ser }, - { "application/set-payment-initiation", ContentType.Setpay }, - { "application/set-registration-initiation", ContentType.Setreg }, - { "application/vnd.spotfire.sfs", ContentType.Sfs }, - { "text/x-sfv", ContentType.Sfv }, - { "image/sgi", ContentType.Sgi }, - { "application/vnd.stardivision.writer-global", ContentType.Sgl }, - { "text/sgml", ContentType.Sgml }, - { "application/x-sh", ContentType.Sh }, - { "application/x-shar", ContentType.Shar }, - { "text/shex", ContentType.Shex }, - { "application/shf+xml", ContentType.Shf }, - { "image/x-mrsid-image", ContentType.Sid }, - { "application/sieve", ContentType.Sieve }, - { "application/pgp-signature", ContentType.Sig }, - { "audio/silk", ContentType.Sil }, - { "application/vnd.symbian.install", ContentType.Sisx }, - { "application/x-stuffit", ContentType.Sit }, - { "application/x-stuffitx", ContentType.Sitx }, - { "application/vnd.koan", ContentType.Skd }, - { "application/vnd.ms-powerpoint.slide.macroenabled.12", ContentType.Sldm }, - { "application/vnd.openxmlformats-officedocument.presentationml.slide", ContentType.Sldx }, - { "text/slim", ContentType.Slim }, - { "application/route-s-tsid+xml", ContentType.Sls }, - { "application/vnd.epson.salt", ContentType.Slt }, - { "application/vnd.stepmania.stepchart", ContentType.Sm }, - { "application/vnd.stardivision.math", ContentType.Smf }, - { "application/smil+xml", ContentType.Smil }, - { "video/x-smv", ContentType.Smv }, - { "application/vnd.stepmania.package", ContentType.Smzip }, - { "application/x-font-snf", ContentType.Snf }, - { "text/spdx", ContentType.Spdx }, - { "application/vnd.yamaha.smaf-phrase", ContentType.Spf }, - { "application/x-futuresplash", ContentType.Spl }, - { "text/vnd.in3d.spot", ContentType.Spot }, - { "application/scvp-vp-response", ContentType.Spp }, - { "application/scvp-vp-request", ContentType.Spq }, - { "application/x-sql", ContentType.Sql }, - { "application/x-wais-source", ContentType.Src }, - { "application/x-subrip", ContentType.Srt }, - { "application/sru+xml", ContentType.Sru }, - { "application/sparql-results+xml", ContentType.Srx }, - { "application/ssdl+xml", ContentType.Ssdl }, - { "application/vnd.kodak-descriptor", ContentType.Sse }, - { "application/vnd.epson.ssf", ContentType.Ssf }, - { "application/ssml+xml", ContentType.Ssml }, - { "application/vnd.sailingtracker.track", ContentType.St }, - { "application/vnd.sun.xml.calc.template", ContentType.Stc }, - { "application/vnd.sun.xml.draw.template", ContentType.Std }, - { "application/vnd.wt.stf", ContentType.Stf }, - { "application/vnd.sun.xml.impress.template", ContentType.Sti }, - { "application/hyperstudio", ContentType.Stk }, - { "application/vnd.ms-pki.stl", ContentType.Stl }, - { "model/step+xml", ContentType.Stpx }, - { "model/step-xml+zip", ContentType.Stpxz }, - { "model/step+zip", ContentType.Stpz }, - { "application/vnd.pg.format", ContentType.Str }, - { "application/vnd.sun.xml.writer.template", ContentType.Stw }, - { "text/stylus", ContentType.Stylus }, - { "image/vnd.dvb.subtitle", ContentType.Sub }, - { "application/vnd.sus-calendar", ContentType.Sus }, - { "application/x-sv4cpio", ContentType.Sv4cpio }, - { "application/x-sv4crc", ContentType.Sv4crc }, - { "application/vnd.dvb.service", ContentType.Svc }, - { "application/vnd.svd", ContentType.Svd }, - { "image/svg+xml", ContentType.Svg }, - { "application/x-shockwave-flash", ContentType.Swf }, - { "application/vnd.aristanetworks.swi", ContentType.Swi }, - { "application/swid+xml", ContentType.Swidtag }, - { "application/vnd.sun.xml.calc", ContentType.Sxc }, - { "application/vnd.sun.xml.draw", ContentType.Sxd }, - { "application/vnd.sun.xml.writer.global", ContentType.Sxg }, - { "application/vnd.sun.xml.impress", ContentType.Sxi }, - { "application/vnd.sun.xml.math", ContentType.Sxm }, - { "application/vnd.sun.xml.writer", ContentType.Sxw }, - { "application/x-t3vm-image", ContentType.T3 }, - { "image/t38", ContentType.T38 }, - { "application/vnd.mynfc", ContentType.Taglet }, - { "application/vnd.tao.intent-module-archive", ContentType.Tao }, - { "image/vnd.tencent.tap", ContentType.Tap }, - { "application/x-tar", ContentType.Tar }, - { "application/vnd.3gpp2.tcap", ContentType.Tcap }, - { "application/x-tcl", ContentType.Tcl }, - { "application/urc-targetdesc+xml", ContentType.Td }, - { "application/vnd.smart.teacher", ContentType.Teacher }, - { "application/tei+xml", ContentType.Tei }, - { "application/x-tex", ContentType.Tex }, - { "application/x-texinfo", ContentType.Texinfo }, - { "text/plain", ContentType.Text }, - { "application/thraud+xml", ContentType.Tfi }, - { "application/x-tex-tfm", ContentType.Tfm }, - { "image/tiff-fx", ContentType.Tfx }, - { "image/x-tga", ContentType.Tga }, - { "application/vnd.ms-officetheme", ContentType.Thmx }, - { "image/tiff", ContentType.Tiff }, - { "application/vnd.tmobile-livetv", ContentType.Tmo }, - { "application/toml", ContentType.Toml }, - { "application/x-bittorrent", ContentType.Torrent }, - { "application/vnd.groove-tool-template", ContentType.Tpl }, - { "application/vnd.trid.tpt", ContentType.Tpt }, - { "application/vnd.trueapp", ContentType.Tra }, - { "application/trig", ContentType.Trig }, - { "application/x-msterminal", ContentType.Trm }, - { "video/mp2t", ContentType.Ts }, - { "application/timestamped-data", ContentType.Tsd }, - { "text/tab-separated-values", ContentType.Tsv }, - { "font/collection", ContentType.Ttc }, - { "font/ttf", ContentType.Ttf }, - { "text/turtle", ContentType.Ttl }, - { "application/ttml+xml", ContentType.Ttml }, - { "application/vnd.simtech-mindmapper", ContentType.Twd }, - { "application/vnd.genomatix.tuxedo", ContentType.Txd }, - { "application/vnd.mobius.txf", ContentType.Txf }, - { "application/x-authorware-bin", ContentType.U32 }, - { "message/global-delivery-status", ContentType.U8dsn }, - { "message/global-headers", ContentType.U8hdr }, - { "message/global-disposition-notification", ContentType.U8mdn }, - { "message/global", ContentType.U8msg }, - { "application/ubjson", ContentType.Ubj }, - { "application/x-debian-package", ContentType.Udeb }, - { "application/vnd.ufdl", ContentType.Ufdl }, - { "application/x-glulx", ContentType.Ulx }, - { "application/vnd.umajin", ContentType.Umj }, - { "application/vnd.unity", ContentType.Unityweb }, - { "application/vnd.uoml+xml", ContentType.Uoml }, - { "text/uri-list", ContentType.Uri }, - { "model/vnd.usdz+zip", ContentType.Usdz }, - { "application/x-ustar", ContentType.Ustar }, - { "application/vnd.uiq.theme", ContentType.Utz }, - { "text/x-uuencode", ContentType.Uu }, - { "audio/vnd.dece.audio", ContentType.Uva }, - { "application/vnd.dece.data", ContentType.Uvd }, - { "image/vnd.dece.graphic", ContentType.Uvg }, - { "video/vnd.dece.hd", ContentType.Uvh }, - { "video/vnd.dece.mobile", ContentType.Uvm }, - { "video/vnd.dece.pd", ContentType.Uvp }, - { "video/vnd.dece.sd", ContentType.Uvs }, - { "application/vnd.dece.ttml+xml", ContentType.Uvt }, - { "video/vnd.uvvu.mp4", ContentType.Uvu }, - { "video/vnd.dece.video", ContentType.Uvv }, - { "application/vnd.dece.zip", ContentType.Uvz }, - { "application/x-virtualbox-vbox", ContentType.Vbox }, - { "text/vcard", ContentType.Vcard }, - { "application/x-cdlink", ContentType.Vcd }, - { "text/x-vcard", ContentType.Vcf }, - { "application/vnd.groove-vcard", ContentType.Vcg }, - { "text/x-vcalendar", ContentType.Vcs }, - { "application/vnd.vcx", ContentType.Vcx }, - { "application/x-virtualbox-vdi", ContentType.Vdi }, - { "model/vnd.sap.vds", ContentType.Vds }, - { "application/x-virtualbox-vhd", ContentType.Vhd }, - { "application/vnd.visionary", ContentType.Vis }, - { "video/vnd.vivo", ContentType.Viv }, - { "application/x-virtualbox-vmdk", ContentType.Vmdk }, - { "video/x-ms-vob", ContentType.Vob }, - { "model/vrml", ContentType.Vrml }, - { "application/vnd.vsf", ContentType.Vsf }, - { "application/vnd.visio", ContentType.Vss }, - { "image/vnd.valve.source.texture", ContentType.Vtf }, - { "text/vtt", ContentType.Vtt }, - { "model/vnd.vtu", ContentType.Vtu }, - { "application/voicexml+xml", ContentType.Vxml }, - { "application/x-doom", ContentType.Wad }, - { "application/vnd.sun.wadl+xml", ContentType.Wadl }, - { "application/wasm", ContentType.Wasm }, - { "audio/wav", ContentType.Wav }, - { "audio/x-ms-wax", ContentType.Wax }, - { "image/vnd.wap.wbmp", ContentType.Wbmp }, - { "application/vnd.criticaltools.wbs+xml", ContentType.Wbs }, - { "application/vnd.wap.wbxml", ContentType.Wbxml }, - { "image/vnd.ms-photo", ContentType.Wdp }, - { "audio/webm", ContentType.Weba }, - { "application/x-web-app-manifest+json", ContentType.Webapp }, - { "video/webm", ContentType.Webm }, - { "image/webp", ContentType.Webp }, - { "application/vnd.pmi.widget", ContentType.Wg }, - { "application/widget", ContentType.Wgt }, - { "application/vnd.ms-works", ContentType.Wks }, - { "video/x-ms-wm", ContentType.Wm }, - { "audio/x-ms-wma", ContentType.Wma }, - { "application/x-ms-wmd", ContentType.Wmd }, - { "application/x-msmetafile", ContentType.Wmf }, - { "text/vnd.wap.wml", ContentType.Wml }, - { "application/vnd.wap.wmlc", ContentType.Wmlc }, - { "text/vnd.wap.wmlscript", ContentType.Wmls }, - { "application/vnd.wap.wmlscriptc", ContentType.Wmlsc }, - { "video/x-ms-wmv", ContentType.Wmv }, - { "video/x-ms-wmx", ContentType.Wmx }, - { "application/x-ms-wmz", ContentType.Wmz }, - { "font/woff", ContentType.Woff }, - { "font/woff2", ContentType.Woff2 }, - { "application/vnd.wordperfect", ContentType.Wpd }, - { "application/vnd.ms-wpl", ContentType.Wpl }, - { "application/vnd.wqd", ContentType.Wqd }, - { "application/x-mswrite", ContentType.Wri }, - { "message/vnd.wfa.wsc", ContentType.Wsc }, - { "application/wsdl+xml", ContentType.Wsdl }, - { "application/wspolicy+xml", ContentType.Wspolicy }, - { "application/vnd.webturbo", ContentType.Wtb }, - { "video/x-ms-wvx", ContentType.Wvx }, - { "model/x3d+xml", ContentType.X3d }, - { "model/x3d+binary", ContentType.X3db }, - { "model/x3d+vrml", ContentType.X3dv }, - { "application/xaml+xml", ContentType.Xaml }, - { "application/x-silverlight-app", ContentType.Xap }, - { "application/vnd.xara", ContentType.Xar }, - { "application/xcap-att+xml", ContentType.Xav }, - { "application/x-ms-xbap", ContentType.Xbap }, - { "application/vnd.fujixerox.docuworks.binder", ContentType.Xbd }, - { "image/x-xbitmap", ContentType.Xbm }, - { "application/xcap-caps+xml", ContentType.Xca }, - { "application/calendar+xml", ContentType.Xcs }, - { "application/xcap-diff+xml", ContentType.Xdf }, - { "application/vnd.syncml.dm+xml", ContentType.Xdm }, - { "application/vnd.adobe.xdp+xml", ContentType.Xdp }, - { "application/dssc+xml", ContentType.Xdssc }, - { "application/vnd.fujixerox.docuworks", ContentType.Xdw }, - { "application/xcap-el+xml", ContentType.Xel }, - { "application/xenc+xml", ContentType.Xenc }, - { "application/patch-ops-error+xml", ContentType.Xer }, - { "application/vnd.adobe.xfdf", ContentType.Xfdf }, - { "application/vnd.xfdl", ContentType.Xfdl }, - { "application/xhtml+xml", ContentType.Xhtml }, - { "image/vnd.xiff", ContentType.Xif }, - { "application/vnd.ms-excel.addin.macroenabled.12", ContentType.Xlam }, - { "application/x-xliff+xml", ContentType.Xlf }, - { "application/vnd.ms-excel", ContentType.Xls }, - { "application/vnd.ms-excel.sheet.binary.macroenabled.12", ContentType.Xlsb }, - { "application/vnd.ms-excel.sheet.macroenabled.12", ContentType.Xlsm }, - { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ContentType.Xlsx }, - { "application/vnd.ms-excel.template.macroenabled.12", ContentType.Xltm }, - { "application/vnd.openxmlformats-officedocument.spreadsheetml.template", ContentType.Xltx }, - { "audio/xm", ContentType.Xm }, - { "application/xml", ContentType.Xml }, - { "application/xcap-ns+xml", ContentType.Xns }, - { "application/vnd.olpc-sugar", ContentType.Xo }, - { "application/xop+xml", ContentType.Xop }, - { "application/x-xpinstall", ContentType.Xpi }, - { "application/xproc+xml", ContentType.Xpl }, - { "image/x-xpixmap", ContentType.Xpm }, - { "application/vnd.is-xpr", ContentType.Xpr }, - { "application/vnd.ms-xpsdocument", ContentType.Xps }, - { "application/vnd.intercon.formnet", ContentType.Xpw }, - { "application/xslt+xml", ContentType.Xslt }, - { "application/vnd.syncml+xml", ContentType.Xsm }, - { "application/vnd.mozilla.xul+xml", ContentType.Xul }, - { "application/xv+xml", ContentType.Xvml }, - { "image/x-xwindowdump", ContentType.Xwd }, - { "chemical/x-xyz", ContentType.Xyz }, - { "application/x-xz", ContentType.Xz }, - { "text/yaml", ContentType.Yaml }, - { "application/yang", ContentType.Yang }, - { "application/yin+xml", ContentType.Yin }, - { "text/x-suse-ymp", ContentType.Ymp }, - { "application/x-zmachine", ContentType.Z1 }, - { "application/vnd.zzazz.deck+xml", ContentType.Zaz }, - { "application/zip", ContentType.Zip }, - { "application/vnd.zul", ContentType.Zir }, - { "application/vnd.handheld-entertainment+xml", ContentType.Zmm }, - }; - } -} diff --git a/Net.Http/src/Helpers/TransportReader.cs b/Net.Http/src/Helpers/TransportReader.cs deleted file mode 100644 index a37bfe9..0000000 --- a/Net.Http/src/Helpers/TransportReader.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: TransportReader.cs -* -* TransportReader.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Text; - -using VNLib.Utils; -using VNLib.Utils.IO; - - -namespace VNLib.Net.Http.Core -{ - - /// <summary> - /// Structure implementation of <see cref="IVnTextReader"/> - /// </summary> - internal struct TransportReader : IVnTextReader - { - ///<inheritdoc/> - public readonly Encoding Encoding => _encoding; - ///<inheritdoc/> - public readonly ReadOnlyMemory<byte> LineTermination => _lineTermination; - ///<inheritdoc/> - public readonly Stream BaseStream => _transport; - - - private readonly SharedHeaderReaderBuffer BinBuffer; - private readonly Encoding _encoding; - private readonly Stream _transport; - private readonly ReadOnlyMemory<byte> _lineTermination; - - private int BufWindowStart; - private int BufWindowEnd; - - /// <summary> - /// Initializes a new <see cref="TransportReader"/> for reading text lines from the transport stream - /// </summary> - /// <param name="transport">The transport stream to read data from</param> - /// <param name="buffer">The shared binary buffer</param> - /// <param name="encoding">The encoding to use when reading bianry</param> - /// <param name="lineTermination">The line delimiter to search for</param> - public TransportReader(Stream transport, SharedHeaderReaderBuffer buffer, Encoding encoding, ReadOnlyMemory<byte> lineTermination) - { - BufWindowEnd = 0; - BufWindowStart = 0; - _encoding = encoding; - _transport = transport; - _lineTermination = lineTermination; - BinBuffer = buffer; - } - - ///<inheritdoc/> - public readonly int Available => BufWindowEnd - BufWindowStart; - - ///<inheritdoc/> - public readonly Span<byte> BufferedDataWindow => BinBuffer.BinBuffer[BufWindowStart..BufWindowEnd]; - - - ///<inheritdoc/> - public void Advance(int count) => BufWindowStart += count; - ///<inheritdoc/> - public void FillBuffer() - { - //Get a buffer from the end of the current window to the end of the buffer - Span<byte> bufferWindow = BinBuffer.BinBuffer[BufWindowEnd..]; - //Read from stream - int read = _transport.Read(bufferWindow); - //Update the end of the buffer window to the end of the read data - BufWindowEnd += read; - } - ///<inheritdoc/> - public ERRNO CompactBufferWindow() - { - //No data to compact if window is not shifted away from start - if (BufWindowStart > 0) - { - //Get span over engire buffer - Span<byte> buffer = BinBuffer.BinBuffer; - //Get data within window - Span<byte> usedData = buffer[BufWindowStart..BufWindowEnd]; - //Copy remaining to the begining of the buffer - usedData.CopyTo(buffer); - //Buffer window start is 0 - BufWindowStart = 0; - //Buffer window end is now the remaining size - BufWindowEnd = usedData.Length; - } - //Return the number of bytes of available space - return BinBuffer.BinLength - BufWindowEnd; - } - } -} diff --git a/Net.Http/src/Helpers/VnWebHeaderCollection.cs b/Net.Http/src/Helpers/VnWebHeaderCollection.cs deleted file mode 100644 index f67e7db..0000000 --- a/Net.Http/src/Helpers/VnWebHeaderCollection.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: VnWebHeaderCollection.cs -* -* VnWebHeaderCollection.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Collections.Generic; - - -namespace VNLib.Net.Http -{ - ///<inheritdoc/> - public sealed class VnWebHeaderCollection : WebHeaderCollection, IEnumerable<KeyValuePair<string?, string?>> - { - IEnumerator<KeyValuePair<string?, string?>> IEnumerable<KeyValuePair<string?, string?>>.GetEnumerator() - { - for (int i = 0; i < Keys.Count; i++) - { - yield return new(Keys[i], Get(i)); - } - } - } -} diff --git a/Net.Http/src/Helpers/WebHeaderExtensions.cs b/Net.Http/src/Helpers/WebHeaderExtensions.cs deleted file mode 100644 index e51bdd5..0000000 --- a/Net.Http/src/Helpers/WebHeaderExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: WebHeaderExtensions.cs -* -* WebHeaderExtensions.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Net; -using System.Runtime.CompilerServices; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Extends the <see cref="WebHeaderCollection"/> to provide some check methods - /// </summary> - public static class WebHeaderExtensions - { - /// <summary> - /// Determines if the specified request header has been set in the current header collection - /// </summary> - /// <param name="headers"></param> - /// <param name="header">Header value to check</param> - /// <returns>true if the header was set, false otherwise</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HeaderSet(this WebHeaderCollection headers, HttpRequestHeader header) => !string.IsNullOrWhiteSpace(headers[header]); - /// <summary> - /// Determines if the specified response header has been set in the current header collection - /// </summary> - /// <param name="headers"></param> - /// <param name="header">Header value to check</param> - /// <returns>true if the header was set, false otherwise</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HeaderSet(this WebHeaderCollection headers, HttpResponseHeader header) => !string.IsNullOrWhiteSpace(headers[header]); - /// <summary> - /// Determines if the specified header has been set in the current header collection - /// </summary> - /// <param name="headers"></param> - /// <param name="header">Header value to check</param> - /// <returns>true if the header was set, false otherwise</returns> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HeaderSet(this WebHeaderCollection headers, string header) => !string.IsNullOrWhiteSpace(headers[header]); - } -}
\ No newline at end of file diff --git a/Net.Http/src/HttpConfig.cs b/Net.Http/src/HttpConfig.cs deleted file mode 100644 index 8e73176..0000000 --- a/Net.Http/src/HttpConfig.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: HttpConfig.cs -* -* HttpConfig.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Text; -using System.IO.Compression; - -using VNLib.Utils.Logging; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Represents configration variables used to create the instance and manage http connections - /// </summary> - public readonly struct HttpConfig - { - public HttpConfig(ILogProvider log) - { - ConnectionKeepAlive = TimeSpan.FromSeconds(100); - ServerLog = log; - } - - /// <summary> - /// A log provider that all server related log entiries will be written to - /// </summary> - public readonly ILogProvider ServerLog { get; } - /// <summary> - /// The absolute request entity body size limit in bytes - /// </summary> - public readonly int MaxUploadSize { get; init; } = 5 * 1000 * 1024; - /// <summary> - /// The maximum size in bytes allowed for an MIME form-data content type upload - /// </summary> - /// <remarks>Set to 0 to disabled mulit-part/form-data uploads</remarks> - public readonly int MaxFormDataUploadSize { get; init; } = 40 * 1024; - /// <summary> - /// The maximum buffer size to use when parsing Multi-part/Form-data file uploads - /// </summary> - /// <remarks> - /// This value is used to create the buffer used to read data from the input stream - /// into memory for parsing. Form-data uploads must be parsed in memory because - /// the data is not delimited by a content length. - /// </remarks> - public readonly int FormDataBufferSize { get; init; } = 8192; - /// <summary> - /// The maximum response entity size in bytes for which the library will allow compresssing response data - /// </summary> - /// <remarks>Set this value to 0 to disable response compression</remarks> - public readonly int CompressionLimit { get; init; } = 1000 * 1024; - /// <summary> - /// The minimum size (in bytes) of respones data that will be compressed - /// </summary> - public readonly int CompressionMinimum { get; init; } = 4096; - /// <summary> - /// The maximum amount of time to listen for data from a connected, but inactive transport connection - /// before closing them - /// </summary> - public readonly TimeSpan ConnectionKeepAlive { get; init; } - /// <summary> - /// The encoding to use when sending and receiving HTTP data - /// </summary> - public readonly Encoding HttpEncoding { get; init; } = Encoding.UTF8; - /// <summary> - /// Sets the compression level for response entity streams of all supported types when - /// compression is used. - /// </summary> - public readonly CompressionLevel CompressionLevel { get; init; } = CompressionLevel.Optimal; - /// <summary> - /// Sets the default Http version for responses when the client version cannot be parsed from the request - /// </summary> - public readonly HttpVersion DefaultHttpVersion { get; init; } = HttpVersion.Http11; - /// <summary> - /// The buffer size used to read HTTP headers from the transport. - /// </summary> - /// <remarks> - /// Setting this value too low will result in header parsing failures - /// and 400 Bad Request responses. Setting it too high can result in - /// resource abuse or high memory usage. 8k is usually a good value. - /// </remarks> - public readonly int HeaderBufferSize { get; init; } = 8192; - /// <summary> - /// The amount of time (in milliseconds) to wait for data on a connection that is in a receive - /// state, aka active receive. - /// </summary> - public readonly int ActiveConnectionRecvTimeout { get; init; } = 5000; - /// <summary> - /// The amount of time (in milliseconds) to wait for data to be send to the client before - /// the connection is closed - /// </summary> - public readonly int SendTimeout { get; init; } = 5000; - /// <summary> - /// The maximum number of request headers allowed per request - /// </summary> - public readonly int MaxRequestHeaderCount { get; init; } = 100; - /// <summary> - /// The maximum number of open transport connections, before 503 errors - /// will be returned and new connections closed. - /// </summary> - /// <remarks>Set to 0 to disable request processing. Causes perminant 503 results</remarks> - public readonly int MaxOpenConnections { get; init; } = int.MaxValue; - /// <summary> - /// The size (in bytes) of the http response header accumulator buffer. - /// </summary> - /// <remarks> - /// Http responses use an internal accumulator to buffer all response headers - /// before writing them to the transport in on write operation. If this value - /// is too low, the response will fail to write. If it is too high, it - /// may cause resource exhaustion or high memory usage. - /// </remarks> - public readonly int ResponseHeaderBufferSize { get; init; } = 16 * 1024; - /// <summary> - /// The size (in bytes) of the buffer to use to discard unread request entity bodies - /// </summary> - public readonly int DiscardBufferSize { get; init; } = 64 * 1024; - /// <summary> - /// The size of the buffer to use when writing response data to the transport - /// </summary> - /// <remarks> - /// This value is the size of the buffer used to copy data from the response - /// entity stream, to the transport stream. - /// </remarks> - public readonly int ResponseBufferSize { get; init; } = 32 * 1024; - /// <summary> - /// The size of the buffer used to accumulate chunked response data before writing to the transport - /// </summary> - public readonly int ChunkedResponseAccumulatorSize { get; init; } = 64 * 1024; - /// <summary> - /// An <see cref="ILogProvider"/> for writing verbose request logs. Set to <c>null</c> - /// to disable verbose request logging - /// </summary> - public readonly ILogProvider? RequestDebugLog { get; init; } = null; - } -}
\ No newline at end of file diff --git a/Net.Http/src/IAlternateProtocol.cs b/Net.Http/src/IAlternateProtocol.cs deleted file mode 100644 index dc7072b..0000000 --- a/Net.Http/src/IAlternateProtocol.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IAlternateProtocol.cs -* -* IAlternateProtocol.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Allows implementation for a protocol swtich from HTTP to another protocol - /// </summary> - public interface IAlternateProtocol - { - /// <summary> - /// Initializes and executes the protocol-switch and the protocol handler - /// that is stored - /// </summary> - /// <param name="transport">The prepared transport stream for the new protocol</param> - /// <param name="handlerToken">A cancelation token that the caller may pass for operation cancelation and cleanup</param> - /// <returns>A task that will be awaited by the server, that when complete, will cleanup resources held by the connection</returns> - Task RunAsync(Stream transport, CancellationToken handlerToken); - } -}
\ No newline at end of file diff --git a/Net.Http/src/IConnectionInfo.cs b/Net.Http/src/IConnectionInfo.cs deleted file mode 100644 index 17ee16f..0000000 --- a/Net.Http/src/IConnectionInfo.cs +++ /dev/null @@ -1,150 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IConnectionInfo.cs -* -* IConnectionInfo.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Text; -using System.Collections.Generic; -using System.Security.Authentication; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Represents a client's connection info as interpreted by the current server - /// </summary> - /// <remarks>Methods and properties are undefined when <see cref="IWebRoot.ClientConnectedAsync(IHttpEvent)"/> returns</remarks> - public interface IConnectionInfo - { - /// <summary> - /// Full request uri of current connection - /// </summary> - Uri RequestUri { get; } - /// <summary> - /// Current request path. Shortcut to <seealso cref="RequestUri"/> <see cref="Uri.LocalPath"/> - /// </summary> - string Path => RequestUri.LocalPath; - /// <summary> - /// Current connection's user-agent header, (may be null if no user-agent header found) - /// </summary> - string? UserAgent { get; } - /// <summary> - /// Current connection's headers - /// </summary> - IHeaderCollection Headers { get; } - /// <summary> - /// A value that indicates if the connection's origin header was set and it's - /// authority segment does not match the <see cref="RequestUri"/> authority - /// segment. - /// </summary> - bool CrossOrigin { get; } - /// <summary> - /// Is the current connecion a websocket request - /// </summary> - bool IsWebSocketRequest { get; } - /// <summary> - /// Request specified content-type - /// </summary> - ContentType ContentType { get; } - /// <summary> - /// Current request's method - /// </summary> - HttpMethod Method { get; } - /// <summary> - /// The current connection's HTTP protocol version - /// </summary> - HttpVersion ProtocolVersion { get; } - /// <summary> - /// Is the connection using transport security? - /// </summary> - bool IsSecure { get; } - /// <summary> - /// The negotiated transport protocol for the current connection - /// </summary> - SslProtocols SecurityProtocol { get; } - /// <summary> - /// Origin header of current connection if specified, null otherwise - /// </summary> - Uri? Origin { get; } - /// <summary> - /// Referer header of current connection if specified, null otherwise - /// </summary> - Uri? Referer { get; } - /// <summary> - /// The parsed range header, or -1,-1 if the range header was not set - /// </summary> - Tuple<long, long>? Range { get; } - /// <summary> - /// The server endpoint that accepted the connection - /// </summary> - IPEndPoint LocalEndpoint { get; } - /// <summary> - /// The raw <see cref="IPEndPoint"/> of the downstream connection. - /// </summary> - IPEndPoint RemoteEndpoint { get; } - /// <summary> - /// The encoding type used to decode and encode character data to and from the current client - /// </summary> - Encoding Encoding { get; } - /// <summary> - /// A <see cref="IReadOnlyDictionary{TKey, TValue}"/> of client request cookies - /// </summary> - IReadOnlyDictionary<string, string> RequestCookies { get; } - /// <summary> - /// Gets an <see cref="IEnumerator{T}"/> for the parsed accept header values - /// </summary> - IEnumerable<string> Accept { get; } - /// <summary> - /// Gets the underlying transport security information for the current connection - /// </summary> - TransportSecurityInfo? TransportSecurity { get; } - - /// <summary> - /// Determines if the client accepts the response content type - /// </summary> - /// <param name="type">The desired content type</param> - /// <returns>True if the client accepts the content type, false otherwise</returns> - bool Accepts(ContentType type); - - /// <summary> - /// Determines if the client accepts the response content type - /// </summary> - /// <param name="contentType">The desired content type</param> - /// <returns>True if the client accepts the content type, false otherwise</returns> - bool Accepts(string contentType); - - /// <summary> - /// Adds a new cookie to the response. If a cookie with the same name and value - /// has been set, the old cookie is replaced with the new one. - /// </summary> - /// <param name="name">Cookie name/id</param> - /// <param name="value">Value to be stored in cookie</param> - /// <param name="domain">Domain for cookie to operate</param> - /// <param name="path">Path to store cookie</param> - /// <param name="Expires">Timespan representing how long the cookie should exist</param> - /// <param name="sameSite">Samesite attribute, Default = Lax</param> - /// <param name="httpOnly">Specify the HttpOnly flag</param> - /// <param name="secure">Specify the Secure flag</param> - void SetCookie(string name, string value, string? domain, string? path, TimeSpan Expires, CookieSameSite sameSite, bool httpOnly, bool secure); - } -}
\ No newline at end of file diff --git a/Net.Http/src/IHeaderCollection.cs b/Net.Http/src/IHeaderCollection.cs deleted file mode 100644 index f7f147a..0000000 --- a/Net.Http/src/IHeaderCollection.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IHeaderCollection.cs -* -* IHeaderCollection.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Net; -using System.Collections.Generic; - -namespace VNLib.Net.Http -{ - /// <summary> - /// The container for request and response headers - /// </summary> - public interface IHeaderCollection - { - /// <summary> - /// Allows for enumeratring all requesest headers - /// </summary> - IEnumerable<KeyValuePair<string, string>> RequestHeaders { get; } - /// <summary> - /// Allows for enumeratring all response headers - /// </summary> - IEnumerable<KeyValuePair<string, string>> ResponseHeaders { get; } - /// <summary> - /// Gets request header, or sets a response header - /// </summary> - /// <param name="index"></param> - /// <returns>Request header with key</returns> - string? this[string index] { get; set; } - /// <summary> - /// Sets a response header only with a response header index - /// </summary> - /// <param name="index">Response header</param> - string this[HttpResponseHeader index] { set; } - /// <summary> - /// Gets a request header - /// </summary> - /// <param name="index">The request header enum </param> - string? this[HttpRequestHeader index] { get; } - /// <summary> - /// Determines if the given header is set in current response headers - /// </summary> - /// <param name="header">Header value to check response headers for</param> - /// <returns>true if header exists in current response headers, false otherwise</returns> - bool HeaderSet(HttpResponseHeader header); - /// <summary> - /// Determines if the given request header is set in current request headers - /// </summary> - /// <param name="header">Header value to check request headers for</param> - /// <returns>true if header exists in current request headers, false otherwise</returns> - bool HeaderSet(HttpRequestHeader header); - - /// <summary> - /// Overwrites (sets) the given response header to the exact value specified - /// </summary> - /// <param name="header">The enumrated header id</param> - /// <param name="value">The value to specify</param> - void Append(HttpResponseHeader header, string? value); - /// <summary> - /// Overwrites (sets) the given response header to the exact value specified - /// </summary> - /// <param name="header">The header name</param> - /// <param name="value">The value to specify</param> - void Append(string header, string? value); - } -}
\ No newline at end of file diff --git a/Net.Http/src/IMemoryResponseEntity.cs b/Net.Http/src/IMemoryResponseEntity.cs deleted file mode 100644 index aa77f58..0000000 --- a/Net.Http/src/IMemoryResponseEntity.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IMemoryResponseEntity.cs -* -* IMemoryResponseEntity.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; - -namespace VNLib.Net.Http -{ - /// <summary> - /// <para> - /// A forward only memory backed response entity body reader. This interface exists - /// to provide a memory-backed response body that will be written "directly" to the - /// response stream. This avoids a buffer allocation and a copy. - /// </para> - /// <para> - /// The entity is only read foward, one time, so it is not seekable. - /// </para> - /// <para> - /// The <see cref="Close"/> method is always called by internal lifecycle hooks - /// when the entity is no longer needed. <see cref="Close"/> should avoid raising - /// excptions. - /// </para> - /// </summary> - public interface IMemoryResponseReader - { - /// <summary> - /// Gets a readonly buffer containing the remaining - /// data to be written - /// </summary> - /// <returns>A memory segment to send to the client</returns> - ReadOnlyMemory<byte> GetMemory(); - - /// <summary> - /// Advances the buffer by the number of bytes written - /// </summary> - /// <param name="written">The number of bytes written</param> - void Advance(int written); - - /// <summary> - /// The number of bytes remaining to send - /// </summary> - int Remaining { get; } - - /// <summary> - /// Raised when reading has completed - /// </summary> - void Close(); - } -}
\ No newline at end of file diff --git a/Net.Http/src/ITransportContext.cs b/Net.Http/src/ITransportContext.cs deleted file mode 100644 index bd6ce05..0000000 --- a/Net.Http/src/ITransportContext.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ITransportContext.cs -* -* ITransportContext.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.IO; -using System.Net; -using System.Threading.Tasks; -using System.Security.Authentication; - - -namespace VNLib.Net.Http -{ - /// <summary> - /// Represents an active connection for application data processing - /// </summary> - public interface ITransportContext - { - /// <summary> - /// The transport network stream for application data marshaling - /// </summary> - Stream ConnectionStream { get; } - /// <summary> - /// The transport security layer security protocol - /// </summary> - SslProtocols SslVersion { get; } - /// <summary> - /// A copy of the local endpoint of the listening socket - /// </summary> - IPEndPoint LocalEndPoint { get; } - /// <summary> - /// The <see cref="IPEndPoint"/> representing the client's connection information - /// </summary> - IPEndPoint RemoteEndpoint { get; } - - /// <summary> - /// Closes the connection when its no longer in use and cleans up held resources. - /// </summary> - /// <returns></returns> - /// <remarks> - /// This method will always be called by the server when a connection is complete - /// regardless of the state of the trasnport - /// </remarks> - ValueTask CloseConnectionAsync(); - - /// <summary> - /// Attemts to get the transport security details for the connection - /// </summary> - /// <returns>A the <see cref="TransportSecurityInfo"/> structure if applicable, null otherwise</returns> - TransportSecurityInfo? GetSecurityInfo(); - } -}
\ No newline at end of file diff --git a/Net.Http/src/ITransportProvider.cs b/Net.Http/src/ITransportProvider.cs deleted file mode 100644 index 13aae57..0000000 --- a/Net.Http/src/ITransportProvider.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: ITransportProvider.cs -* -* ITransportProvider.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Threading; -using System.Threading.Tasks; - -namespace VNLib.Net.Http -{ - /// <summary> - /// Listens for network connections and captures the information - /// required for application processing - /// </summary> - public interface ITransportProvider - { - /// <summary> - /// Begins listening for connections (binds a socket if necessary) and is - /// called before the server begins listening for connections. - /// </summary> - /// <param name="stopToken">A token that is cancelled when the server is closed</param> - void Start(CancellationToken stopToken); - - /// <summary> - /// Waits for a new connection to be established and returns its context. This method - /// should only return an established connection (ie: connected socket). - /// </summary> - /// <param name="cancellation">A token to cancel the wait operation</param> - /// <returns>A <see cref="ValueTask"/> that returns an established connection</returns> - ValueTask<ITransportContext> AcceptAsync(CancellationToken cancellation); - } -}
\ No newline at end of file diff --git a/Net.Http/src/IWebRoot.cs b/Net.Http/src/IWebRoot.cs deleted file mode 100644 index 9b1a9c8..0000000 --- a/Net.Http/src/IWebRoot.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: IWebRoot.cs -* -* IWebRoot.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Threading.Tasks; -using System.Collections.Generic; - - -namespace VNLib.Net.Http -{ - /// <summary> - /// Represents a root identifying the main endpoints of the server, and the primary processing actions - /// for requests to this endpoint - /// </summary> - public interface IWebRoot - { - /// <summary> - /// The hostname the server will listen for, and the hostname that will identify this root when a connection requests it - /// </summary> - string Hostname { get; } - /// <summary> - /// <para> - /// The main event handler for user code to process a request - /// </para> - /// <para> - /// NOTE: This function must be thread-safe! - /// </para> - /// </summary> - /// <param name="httpEvent">An active, unprocessed event capturing the request infomration into a standard format</param> - /// <returns>A <see cref="ValueTask"/> that the processor will await until the entity has been processed</returns> - ValueTask ClientConnectedAsync(IHttpEvent httpEvent); - /// <summary> - /// "Low-Level" 301 redirects - /// </summary> - IReadOnlyDictionary<string, Redirect> Redirects { get; } - } -}
\ No newline at end of file diff --git a/Net.Http/src/TransportSecurityInfo.cs b/Net.Http/src/TransportSecurityInfo.cs deleted file mode 100644 index 7c7a79c..0000000 --- a/Net.Http/src/TransportSecurityInfo.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Http -* File: TransportSecurityInfo.cs -* -* TransportSecurityInfo.cs is part of VNLib.Net.Http which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Http is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Http is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Net.Security; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; - - -namespace VNLib.Net.Http -{ - - /// <summary> - /// Gets the transport TLS security information for the current connection - /// </summary> - public readonly struct TransportSecurityInfo - { - /// <summary> - /// Gets a Boolean value that indicates whether the certificate revocation list is checked during the certificate validation process. - /// </summary> - /// <returns>true if the certificate revocation list is checked during validation; otherwise, false.</returns> - public readonly bool CheckCertRevocationStatus { get; init; } - - /// <summary> - /// Gets a value that identifies the bulk encryption algorithm used by the connection. - /// </summary> - public readonly CipherAlgorithmType CipherAlgorithm { get; init; } - - /// <summary> - /// Gets a value that identifies the strength of the cipher algorithm used by the connection. - /// </summary> - public readonly int CipherStrength { get; init; } - - /// <summary> - /// Gets the algorithm used for generating message authentication codes (MACs). - /// </summary> - public readonly HashAlgorithmType HashAlgorithm { get; init; } - - /// <summary> - /// Gets a value that identifies the strength of the hash algorithm used by this instance. - /// </summary> - public readonly int HashStrength { get; init; } - - /// <summary> - /// Gets a Boolean value that indicates whether authentication was successful. - /// </summary> - public readonly bool IsAuthenticated { get; init; } - - /// <summary> - /// Gets a Boolean value that indicates whether this connection uses data encryption. - /// </summary> - public readonly bool IsEncrypted { get; init; } - - /// <summary> - /// Gets a Boolean value that indicates whether both server and client have been authenticated. - /// </summary> - public readonly bool IsMutuallyAuthenticated { get; init; } - - /// <summary> - /// Gets a Boolean value that indicates whether the data sent using this connection is signed. - /// </summary> - public readonly bool IsSigned { get; init; } - - /// <summary> - /// Gets the key exchange algorithm used by this connection - /// </summary> - public readonly ExchangeAlgorithmType KeyExchangeAlgorithm { get; init; } - - /// <summary> - /// Gets a value that identifies the strength of the key exchange algorithm used by the transport connection - /// </summary> - public readonly int KeyExchangeStrength { get; init; } - - /// <summary> - /// Gets the certificate used to authenticate the local endpoint. - /// </summary> - public readonly X509Certificate? LocalCertificate { get; init; } - - /// <summary> - /// The negotiated application protocol in TLS handshake. - /// </summary> - public readonly SslApplicationProtocol NegotiatedApplicationProtocol { get; init; } - - /// <summary> - /// Gets the cipher suite which was negotiated for this connection. - /// </summary> - public readonly TlsCipherSuite NegotiatedCipherSuite { get; init; } - - /// <summary> - /// Gets the certificate used to authenticate the remote endpoint. - /// </summary> - public readonly X509Certificate? RemoteCertificate { get; init; } - - /// <summary> - /// Gets the TransportContext used for authentication using extended protection. - /// </summary> - public readonly TransportContext TransportContext { get; init; } - } -} diff --git a/Net.Http/src/VNLib.Net.Http.csproj b/Net.Http/src/VNLib.Net.Http.csproj deleted file mode 100644 index 30e698c..0000000 --- a/Net.Http/src/VNLib.Net.Http.csproj +++ /dev/null @@ -1,57 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <TargetFramework>net6.0</TargetFramework> - <RootNamespace>VNLib.Net.Http</RootNamespace> - <Authors>Vaughn Nugent</Authors> - <Company>$(Authors)</Company> - <Product>VNLib HTTP Library</Product> - <Description>Provides a high performance HTTP 0.9-1.1 application processing layer for handling transport *agnostic connections and asynchronous event support for applications serving HTTP -requests such as web content. This library has a large focus on low/no GC allocations using unmanaged memory support provided by the VNLib.Utils library. No external dependencies -outside of the VNLib ecosystem are required. The VNLib.Plugins and VNLib.Plugins.Essentials libraries are highly recommended for serving web content.</Description> - <Copyright>Copyright © 2022 Vaughn Nugent</Copyright> - <PackageId>VNLib.Net.Http</PackageId> - <Version>1.0.1.5</Version> - <NeutralLanguage>en-US</NeutralLanguage> - <PackageProjectUrl>https://www.vaughnnugent.com/resources</PackageProjectUrl> - <AssemblyName>VNLib.Net.Http</AssemblyName> - <Nullable>enable</Nullable> - <GenerateDocumentationFile>True</GenerateDocumentationFile> - <AnalysisLevel>latest-all</AnalysisLevel> - <SignAssembly>True</SignAssembly> - <AssemblyOriginatorKeyFile>\\vaughnnugent.com\Internal\Folder Redirection\vman\Documents\Programming\Software\StrongNameingKey.snk</AssemblyOriginatorKeyFile> - </PropertyGroup> - - <!-- Resolve nuget dll files and store them in the output dir --> - <PropertyGroup> - <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> - </PropertyGroup> - - <PropertyGroup Condition="'$(Configuration)'=='Debug'"> - <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> - </PropertyGroup> - - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> - <Deterministic>False</Deterministic> - </PropertyGroup> - - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> - <Deterministic>False</Deterministic> - </PropertyGroup> - - <ItemGroup> - <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> - <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2"> - <PrivateAssets>all</PrivateAssets> - <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> - </PackageReference> - </ItemGroup> - - <ItemGroup> - <ProjectReference Include="..\..\Utils\src\VNLib.Utils.csproj" /> - </ItemGroup> - -</Project> |