aboutsummaryrefslogtreecommitdiff
path: root/Net.Http/src
diff options
context:
space:
mode:
Diffstat (limited to 'Net.Http/src')
-rw-r--r--Net.Http/src/AlternateProtocolBase.cs96
-rw-r--r--Net.Http/src/ConnectionInfo.cs166
-rw-r--r--Net.Http/src/Core/HttpContext.cs170
-rw-r--r--Net.Http/src/Core/HttpCookie.cs125
-rw-r--r--Net.Http/src/Core/HttpEvent.cs141
-rw-r--r--Net.Http/src/Core/HttpServerBase.cs312
-rw-r--r--Net.Http/src/Core/HttpServerProcessing.cs387
-rw-r--r--Net.Http/src/Core/IConnectionContext.cs62
-rw-r--r--Net.Http/src/Core/IHttpEvent.cs104
-rw-r--r--Net.Http/src/Core/IHttpLifeCycle.cs62
-rw-r--r--Net.Http/src/Core/IHttpResponseBody.cs73
-rw-r--r--Net.Http/src/Core/Request/HttpInputStream.cs222
-rw-r--r--Net.Http/src/Core/Request/HttpRequest.cs284
-rw-r--r--Net.Http/src/Core/Request/HttpRequestBody.cs70
-rw-r--r--Net.Http/src/Core/Request/HttpRequestExtensions.cs304
-rw-r--r--Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs533
-rw-r--r--Net.Http/src/Core/Response/ChunkDataAccumulator.cs228
-rw-r--r--Net.Http/src/Core/Response/ChunkedStream.cs249
-rw-r--r--Net.Http/src/Core/Response/DirectStream.cs96
-rw-r--r--Net.Http/src/Core/Response/HeaderDataAccumulator.cs157
-rw-r--r--Net.Http/src/Core/Response/HttpContextExtensions.cs124
-rw-r--r--Net.Http/src/Core/Response/HttpContextResponseWriting.cs253
-rw-r--r--Net.Http/src/Core/Response/HttpResponse.cs307
-rw-r--r--Net.Http/src/Core/Response/ResponseWriter.cs182
-rw-r--r--Net.Http/src/Core/SharedHeaderReaderBuffer.cs85
-rw-r--r--Net.Http/src/Core/VnHeaderCollection.cs75
-rw-r--r--Net.Http/src/Exceptions/ContentTypeException.cs43
-rw-r--r--Net.Http/src/Exceptions/TerminateConnectionException.cs57
-rw-r--r--Net.Http/src/FileUpload.cs122
-rw-r--r--Net.Http/src/Helpers/AlternateProtocolTransportStreamWrapper.cs50
-rw-r--r--Net.Http/src/Helpers/ContentType.cs1180
-rw-r--r--Net.Http/src/Helpers/CoreBufferHelpers.cs188
-rw-r--r--Net.Http/src/Helpers/HelperTypes.cs98
-rw-r--r--Net.Http/src/Helpers/HttpHelpers.cs445
-rw-r--r--Net.Http/src/Helpers/MimeLookups.cs3237
-rw-r--r--Net.Http/src/Helpers/TransportReader.cs114
-rw-r--r--Net.Http/src/Helpers/VnWebHeaderCollection.cs43
-rw-r--r--Net.Http/src/Helpers/WebHeaderExtensions.cs60
-rw-r--r--Net.Http/src/HttpConfig.cs154
-rw-r--r--Net.Http/src/IAlternateProtocol.cs46
-rw-r--r--Net.Http/src/IConnectionInfo.cs150
-rw-r--r--Net.Http/src/IHeaderCollection.cs85
-rw-r--r--Net.Http/src/IMemoryResponseEntity.cs69
-rw-r--r--Net.Http/src/ITransportContext.cs71
-rw-r--r--Net.Http/src/ITransportProvider.cs51
-rw-r--r--Net.Http/src/IWebRoot.cs58
-rw-r--r--Net.Http/src/TransportSecurityInfo.cs121
-rw-r--r--Net.Http/src/VNLib.Net.Http.csproj57
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>