diff options
Diffstat (limited to 'apps/VNLib.WebServer/src/Config')
15 files changed, 1096 insertions, 0 deletions
diff --git a/apps/VNLib.WebServer/src/Config/IServerConfig.cs b/apps/VNLib.WebServer/src/Config/IServerConfig.cs new file mode 100644 index 0000000..b0b06ba --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/IServerConfig.cs @@ -0,0 +1,34 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: IServerConfig.cs +* +* IServerConfig.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json; + + +namespace VNLib.WebServer.Config +{ + internal interface IServerConfig + { + JsonElement GetDocumentRoot(); + } +} diff --git a/apps/VNLib.WebServer/src/Config/JsonConfigOptions.cs b/apps/VNLib.WebServer/src/Config/JsonConfigOptions.cs new file mode 100644 index 0000000..a48b4e9 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/JsonConfigOptions.cs @@ -0,0 +1,42 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: JsonConfigOptions.cs +* +* JsonConfigOptions.cs is part of VNLib.WebServer which is part of +* the larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json; + +namespace VNLib.WebServer.Config +{ + internal static class JsonConfigOptions + { + private static readonly JsonSerializerOptions _ops = new() + { + AllowTrailingCommas = true, + ReadCommentHandling = JsonCommentHandling.Skip, + }; + + public static T? DeserializeElement<T>(this JsonElement el) + { + return el.Deserialize<T>(_ops); + } + } +} diff --git a/apps/VNLib.WebServer/src/Config/JsonServerConfig.cs b/apps/VNLib.WebServer/src/Config/JsonServerConfig.cs new file mode 100644 index 0000000..ada9902 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/JsonServerConfig.cs @@ -0,0 +1,156 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: JsonServerConfig.cs +* +* JsonServerConfig.cs is part of VNLib.WebServer which is part +* of the larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.IO; +using System.Text.Json; + +using YamlDotNet.Core.Events; +using YamlDotNet.Serialization; + +using VNLib.Utils.IO; + +namespace VNLib.WebServer.Config +{ + internal sealed class JsonServerConfig(JsonDocument doc) : IServerConfig + { + public JsonElement GetDocumentRoot() => doc.RootElement; + + public static JsonServerConfig? FromFile(string filename) + { + string nameOnly = Path.GetFileName(filename); + Console.WriteLine("Loading configuration file from {0}", nameOnly); + + if (filename.EndsWith(".json")) + { + return FromJson(filename); + } + else if (filename.EndsWith(".yaml") || filename.EndsWith(".yml")) + { + return FromYaml(filename); + } + else + { + return null; + } + } + + /// <summary> + /// Reads a server configuration from the specified JSON document + /// </summary> + /// <param name="configPath">The file path of the json cofiguration file</param> + /// <returns>A new <see cref="JsonServerConfig"/> wrapping the server config</returns> + public static JsonServerConfig? FromJson(string fileName) + { + if (!FileOperations.FileExists(fileName)) + { + return null; + } + + //Open the config file + using FileStream fs = File.OpenRead(fileName); + + //Allow comments + JsonDocumentOptions jdo = new() + { + CommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true, + }; + + return new JsonServerConfig(JsonDocument.Parse(fs, jdo)); + } + + public static JsonServerConfig? FromYaml(string fileName) + { + if (!FileOperations.FileExists(fileName)) + { + return null; + } + + /* + * The following code reads the configuration as a yaml + * object and then serializes it over to json. + */ + + using StreamReader reader = OpenFileRead(fileName); + + object? yamlObject = new DeserializerBuilder() + .WithNodeTypeResolver(new NumberTypeResolver()) + .Build() + .Deserialize(reader); + + ISerializer serializer = new SerializerBuilder() + .JsonCompatible() + .Build(); + + using VnMemoryStream ms = new(); + using (StreamWriter sw = new(ms, leaveOpen: true)) + { + serializer.Serialize(sw, yamlObject); + } + + ms.Seek(0, SeekOrigin.Begin); + + return new JsonServerConfig(JsonDocument.Parse(ms)); + } + + private static StreamReader OpenFileRead(string fileName) + { + return new StreamReader( + stream: File.OpenRead(fileName), + encoding: System.Text.Encoding.UTF8, + detectEncodingFromByteOrderMarks: false, + leaveOpen: false + ); + } + + public class NumberTypeResolver : INodeTypeResolver + { + public bool Resolve(NodeEvent? nodeEvent, ref Type currentType) + { + if (nodeEvent is Scalar scalar) + { + if(long.TryParse(scalar.Value, out _)) + { + currentType = typeof(int); + return true; + } + + if (double.TryParse(scalar.Value, out _)) + { + currentType = typeof(double); + return true; + } + + if (bool.TryParse(scalar.Value, out _)) + { + currentType = typeof(bool); + return true; + } + } + return false; + } + } + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/BenchmarkConfig.cs b/apps/VNLib.WebServer/src/Config/Model/BenchmarkConfig.cs new file mode 100644 index 0000000..1b0f157 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/BenchmarkConfig.cs @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: BenchmarkConfig.cs +* +* BenchmarkConfig.cs is part of VNLib.WebServer which is part of the +* larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + + internal sealed class BenchmarkConfig + { + + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } + + [JsonPropertyName("size")] + public int Size { get; set; } + + [JsonPropertyName("random")] + public bool Random { get; set; } + + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/CorsSecurityConfig.cs b/apps/VNLib.WebServer/src/Config/Model/CorsSecurityConfig.cs new file mode 100644 index 0000000..2f95697 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/CorsSecurityConfig.cs @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: CorsSecurityConfig.cs +* +* CorsSecurityConfig.cs is part of VNLib.WebServer which is part of the +* larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal class CorsSecurityConfig + { + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } = false; + + [JsonPropertyName("deny_cors_connections")] + public bool DenyCorsCons { get; set; } = false; + + [JsonPropertyName("allowed_authority")] + public string[] AllowedCorsAuthority { get; set; } = Array.Empty<string>(); + } +}
\ No newline at end of file diff --git a/apps/VNLib.WebServer/src/Config/Model/ErrorFileConfig.cs b/apps/VNLib.WebServer/src/Config/Model/ErrorFileConfig.cs new file mode 100644 index 0000000..c4355d6 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/ErrorFileConfig.cs @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: ErrorFileConfig.cs +* +* ErrorFileConfig.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal sealed class ErrorFileConfig + { + [JsonPropertyName("code")] + public int Code { get; set; } + + [JsonPropertyName("path")] + public string? Path { get; set; } + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/HttpCompressorConfig.cs b/apps/VNLib.WebServer/src/Config/Model/HttpCompressorConfig.cs new file mode 100644 index 0000000..eb8e68c --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/HttpCompressorConfig.cs @@ -0,0 +1,47 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: HttpCompressorConfig.cs +* +* HttpCompressorConfig.cs is part of VNLib.WebServer which is part of +* the larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal sealed class HttpCompressorConfig + { + [JsonPropertyName("assembly")] + public string? AssemblyPath { get; set; } + + /// <summary> + /// If this compressor is enabled. The default is true, to use built-in + /// compressors. + /// </summary> + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } = true; + + [JsonPropertyName("max_size")] + public long CompressionMax { get; set; } = 104857600; //100MB + + [JsonPropertyName("min_size")] + public int CompressionMin { get; set; } = 256; + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/HttpGlobalConfig.cs b/apps/VNLib.WebServer/src/Config/Model/HttpGlobalConfig.cs new file mode 100644 index 0000000..22bfe75 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/HttpGlobalConfig.cs @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: HttpGlobalConfig.cs +* +* HttpGlobalConfig.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal class HttpGlobalConfig + { + + [JsonPropertyName("default_version")] + public string DefaultHttpVersion { get; set; } = "HTTP/1.1"; + + /// <summary> + /// The maximum size of a request entity that can be sent to the server. + /// </summary> + [JsonPropertyName("max_entity_size")] + public long MaxEntitySize { get; set; } = long.MaxValue; + + /// <summary> + /// The maximum size of a multipart form data upload. + /// </summary> + [JsonPropertyName("multipart_max_size")] + public int MultipartMaxSize { get; set; } = 1048576; //1MB + + /// <summary> + /// The time in milliseconds for an HTTP/1.1 connection to remain open + /// before the server closes it. + /// </summary> + [JsonPropertyName("keepalive_ms")] + public int KeepAliveMs { get; set; } = 60000; //60 seconds + + /// <summary> + /// The time in milliseconds to wait for data on an active connection. + /// IE: A connection that has been established and has signaled that + /// it is ready to transfer data. + /// </summary> + [JsonPropertyName("recv_timeout_ms")] + public int RecvTimeoutMs { get; set; } = 5000; //5 seconds + + /// <summary> + /// The time in milliseconds to wait for data to be sent on a connection. + /// </summary> + [JsonPropertyName("send_timeout_ms")] + public int SendTimeoutMs { get; set; } = 60000; //60 seconds + + /// <summary> + /// The maximum number of headers that can be sent in a request. + /// </summary> + [JsonPropertyName("max_request_header_count")] + public int MaxRequestHeaderCount { get; set; } = 32; + + /// <summary> + /// The maximum number of open connections that can be made to the server, before + /// the server starts rejecting new connections. + /// </summary> + [JsonPropertyName("max_connections")] + public int MaxConnections { get; set; } = int.MaxValue; + + /// <summary> + /// The maximum number of uploads that can be made in a single request. If + /// this value is exceeded, the request will be rejected. + /// </summary> + [JsonPropertyName("max_uploads_per_request")] + public ushort MaxUploadsPerRequest { get; set; } = 10; + + /// <summary> + /// The size of the buffer used to store request headers. + /// </summary> + [JsonPropertyName("header_buf_size")] + public int HeaderBufSize { get; set; } + + /// <summary> + /// The size of the buffer used to store response headers. + /// </summary> + [JsonPropertyName("response_header_buf_size")] + public int ResponseHeaderBufSize { get; set; } + + /// <summary> + /// The size of the buffer used to store form data. + /// </summary> + [JsonPropertyName("multipart_max_buf_size")] + public int MultipartMaxBufSize { get; set; } + + /// <summary> + /// The configuration for the HTTP compression settings. + /// </summary> + [JsonPropertyName("compression")] + public HttpCompressorConfig? Compression { get; set; } = new(); + + public void ValidateConfig() + { + Validate.EnsureNotNull(DefaultHttpVersion, "Default HTTP version is required"); + + Validate.EnsureRange(MaxEntitySize, 0, long.MaxValue); + Validate.EnsureRange(MultipartMaxSize, -1, int.MaxValue); + Validate.EnsureRange(KeepAliveMs, -1, int.MaxValue); + + //Timeouts may be disabled by setting 0 or -1. Both are allowed for readability + Validate.EnsureRange(RecvTimeoutMs, -2, int.MaxValue); + Validate.EnsureRange(SendTimeoutMs, -2, int.MaxValue); + + Validate.EnsureRange(MaxRequestHeaderCount, 0, 1024); + Validate.EnsureRange(MaxConnections, 0, int.MaxValue); + Validate.EnsureRange(MaxUploadsPerRequest, 0, 1024); + Validate.EnsureRange(HeaderBufSize, 0, int.MaxValue); + Validate.EnsureRange(ResponseHeaderBufSize, 0, int.MaxValue); + Validate.EnsureRange(MultipartMaxBufSize, 0, int.MaxValue); + + //Validate compression config + Validate.EnsureNotNull(Compression, "Compression configuration should not be set to null. Comment to enable defaults"); + Validate.EnsureRange(Compression.CompressionMax, -1, long.MaxValue); + Validate.EnsureRange(Compression.CompressionMin, -1, int.MaxValue); + } + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/LogConfig.cs b/apps/VNLib.WebServer/src/Config/Model/LogConfig.cs new file mode 100644 index 0000000..fafd630 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/LogConfig.cs @@ -0,0 +1,52 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: LogConfig.cs +* +* LogConfig.cs is part of VNLib.WebServer which is part of the +* larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal sealed class LogConfig + { + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } = false; + + [JsonPropertyName("path")] + public string? Path { get; set; } + + [JsonPropertyName("template")] + public string? Template { get; set; } + + [JsonPropertyName("flush_sec")] + public int FlushIntervalSeconds { get; set; } = 10; + + [JsonPropertyName("retained_files")] + public int RetainedFiles { get; set; } = 31; + + [JsonPropertyName("file_size_limit")] + public int FileSizeLimit { get; set; } = 500 * 1000 * 1024; + + [JsonPropertyName("interval")] + public string Interval { get; set; } = "infinite"; + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/ServerPluginConfig.cs b/apps/VNLib.WebServer/src/Config/Model/ServerPluginConfig.cs new file mode 100644 index 0000000..42b91b1 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/ServerPluginConfig.cs @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: ServerPluginConfig.cs +* +* ServerPluginConfig.cs is part of VNLib.WebServer which is part of +* the larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal class ServerPluginConfig + { + [JsonPropertyName("enabled")] + public bool Enabled { get; set; } = true; //default to true if config is defined, then it can be assumed we want to load plugins unless explicitly disabled + + [JsonPropertyName("path")] + public string? Path { get; set; } + + [JsonPropertyName("config_dir")] + public string? ConfigDir { get; set; } + + [JsonPropertyName("hot_reload")] + public bool HotReload { get; set; } + + [JsonPropertyName("reload_delay_sec")] + public int ReloadDelaySec { get; set; } = 2; + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/TcpConfigJson.cs b/apps/VNLib.WebServer/src/Config/Model/TcpConfigJson.cs new file mode 100644 index 0000000..5bd2b94 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/TcpConfigJson.cs @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: TcpServerLoader.cs +* +* TcpServerLoader.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal sealed class TcpConfigJson + { + [JsonPropertyName("keepalive_sec")] + public int TcpKeepAliveTime { get; set; } = 4; + + [JsonPropertyName("keepalive_interval_sec")] + public int KeepaliveInterval { get; set; } = 4; + + [JsonPropertyName("max_recv_buffer")] + public int MaxRecvBufferData { get; set; } = 10 * 64 * 1024; + + [JsonPropertyName("backlog")] + public int BackLog { get; set; } = 1000; + + [JsonPropertyName("max_connections")] + public long MaxConnections { get; set; } = long.MaxValue; + + [JsonPropertyName("no_delay")] + public bool NoDelay { get; set; } = false; + + /* + * Buffer sizes are a pain, this is a good default size for medium bandwith connections (100mbps) + * using the BDP calculations + * + * BDP = Bandwidth * RTT + */ + + [JsonPropertyName("tx_buffer")] + public int TcpSendBufferSize { get; set; } = 625 * 1024; + + [JsonPropertyName("rx_buffer")] + public int TcpRecvBufferSize { get; set; } = 625 * 1024; + + + public void ValidateConfig() + { + Validate.EnsureRange(TcpKeepAliveTime, 0, 60); + Validate.EnsureRange(KeepaliveInterval, 0, 60); + Validate.EnsureRange(BackLog, 0, 10000); + Validate.EnsureRange(MaxConnections, 0, long.MaxValue); + Validate.EnsureRange(MaxRecvBufferData, 0, 10 * 1024 * 1024); //10MB + Validate.EnsureRange(TcpSendBufferSize, 0, 10 * 1024 * 1024); //10MB + } + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/TransportInterface.cs b/apps/VNLib.WebServer/src/Config/Model/TransportInterface.cs new file mode 100644 index 0000000..e0e2551 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/TransportInterface.cs @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: TransportInterface.cs +* +* TransportInterface.cs is part of VNLib.WebServer which is part of +* the larger VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.IO; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Text.Json.Serialization; + +using VNLib.Utils.Memory; +using VNLib.Utils.Resources; + +namespace VNLib.WebServer.Config.Model +{ + /// <summary> + /// Represents a transport interface configuration element for a virtual host + /// </summary> + internal class TransportInterface + { + [JsonPropertyName("port")] + public int Port { get; set; } + + [JsonPropertyName("address")] + public string? Address { get; set; } + + [JsonPropertyName("certificate")] + public string? Cert { get; set; } + + [JsonPropertyName("private_key")] + public string? PrivKey { get; set; } + + [JsonPropertyName("ssl")] + public bool Ssl { get; set; } + + [JsonPropertyName("client_cert_required")] + public bool ClientCertRequired { get; set; } + + [JsonPropertyName("password")] + public string? PrivKeyPassword { get; set; } + + [JsonPropertyName("use_os_ciphers")] + public bool UseOsCiphers { get; set; } + + public IPEndPoint GetEndpoint() + { + IPAddress addr = string.IsNullOrEmpty(Address) ? IPAddress.Any : IPAddress.Parse(Address); + return new IPEndPoint(addr, Port); + } + + public X509Certificate? LoadCertificate() + { + if (!Ssl) + { + return null; + } + + Validate.EnsureNotNull(Cert, "TLS Certificate is required when ssl is enabled"); + Validate.FileExists(Cert); + + X509Certificate? cert = null; + + /* + * Default to use a PEM encoded certificate and private key file. Unless the file + * is a pfx file, then we will use the private key from the pfx file. + */ + + if (Path.GetExtension(Cert).EndsWith("pfx", StringComparison.OrdinalIgnoreCase)) + { + //Create from pfx file including private key + cert = X509Certificate.CreateFromCertFile(Cert); + } + else + { + Validate.EnsureNotNull(PrivKey, "TLS Private Key is required ssl is enabled"); + Validate.FileExists(PrivKey); + + /* + * Attempt to capture the private key password. This will wrap the + * string in a private string instance, and setting the value to true + * will ensure the password memory is wiped when this function returns + */ + using PrivateString? password = PrivateString.ToPrivateString(PrivKeyPassword, true); + + //Load the cert and decrypt with password if set + using X509Certificate2 cert2 = password == null ? X509Certificate2.CreateFromPemFile(Cert, PrivKey) + : X509Certificate2.CreateFromEncryptedPemFile(Cert, password.ToReadOnlySpan(), PrivKey); + + /* + * Workaround for a silly Windows SecureChannel module bug for parsing + * X509Certificate2 from pem cert and private key files. + * + * Must export into pkcs12 format then create a new X509Certificate2 from the + * exported bytes. + */ + + //Copy the cert in pkcs12 format + byte[] pkcs = cert2.Export(X509ContentType.Pkcs12); + cert = new X509Certificate2(pkcs); + MemoryUtil.InitializeBlock(pkcs); + } + + return cert; + } + + /// <summary> + /// Builds a deterministic hash-code base on the configuration state. + /// </summary> + /// <returns>The hash-code that represents the current instance</returns> + public override int GetHashCode() => HashCode.Combine(Address, Port); + + public override bool Equals(object? obj) => obj is TransportInterface iface && GetHashCode() == iface.GetHashCode(); + + public override string ToString() => $"[{Address}:{Port}]"; + + } +} diff --git a/apps/VNLib.WebServer/src/Config/Model/VirtualHostServerConfig.cs b/apps/VNLib.WebServer/src/Config/Model/VirtualHostServerConfig.cs new file mode 100644 index 0000000..5734bd3 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Model/VirtualHostServerConfig.cs @@ -0,0 +1,98 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: VirtualHostServerConfig.cs +* +* VirtualHostServerConfig.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace VNLib.WebServer.Config.Model +{ + internal sealed class VirtualHostServerConfig + { + [JsonPropertyName("trace")] + public bool RequestTrace { get; set; } = false; + + [JsonPropertyName("force_port_check")] + public bool ForcePortCheck { get; set; } = false; + + [JsonPropertyName("benchmark")] + public BenchmarkConfig? Benchmark { get; set; } + + [JsonPropertyName("interfaces")] + public TransportInterface[] Interfaces { get; set; } = Array.Empty<TransportInterface>(); + + [JsonPropertyName("hostnames")] + public string[]? Hostnames { get; set; } = Array.Empty<string>(); + + [JsonPropertyName("hostname")] + public string? Hostname + { + get => Hostnames?.FirstOrDefault(); + set + { + if (value != null) + { + Hostnames = [value]; + } + } + } + + [JsonPropertyName("path")] + public string? DirPath { get; set; } = string.Empty; + + [JsonPropertyName("downstream_servers")] + public string[] DownstreamServers { get; set; } = Array.Empty<string>(); + + [JsonPropertyName("whitelist")] + public string[]? Whitelist { get; set; } + + [JsonPropertyName("blacklist")] + public string[]? Blacklist { get; set; } + + [JsonPropertyName("deny_extensions")] + public string[]? DenyExtensions { get; set; } + + [JsonPropertyName("default_files")] + public string[]? DefaultFiles { get; set; } + + [JsonPropertyName("headers")] + public Dictionary<string, string> Headers { get; set; } = []; + + [JsonPropertyName("cors")] + public CorsSecurityConfig Cors { get; set; } = new(); + + [JsonPropertyName("error_files")] + public ErrorFileConfig[] ErrorFiles { get; set; } = Array.Empty<ErrorFileConfig>(); + + [JsonPropertyName("cache_default_sec")] + public int CacheDefaultTimeSeconds { get; set; } = 0; + + [JsonPropertyName("path_filter")] + public string? PathFilter { get; set; } + + [JsonPropertyName("max_execution_time_ms")] + public int MaxExecutionTimeMs { get; set; } = 20000; + } +} diff --git a/apps/VNLib.WebServer/src/Config/ServerConfigurationException.cs b/apps/VNLib.WebServer/src/Config/ServerConfigurationException.cs new file mode 100644 index 0000000..39c18e5 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/ServerConfigurationException.cs @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: ServerConfigurationException.cs +* +* ServerConfigurationException.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; + +namespace VNLib.WebServer.Config +{ + public class ServerConfigurationException : Exception + { + public ServerConfigurationException() + { } + + public ServerConfigurationException(string? message) : base(message) + { } + + public ServerConfigurationException(string? message, Exception? innerException) : base(message, innerException) + { } + } +} diff --git a/apps/VNLib.WebServer/src/Config/Validate.cs b/apps/VNLib.WebServer/src/Config/Validate.cs new file mode 100644 index 0000000..773d787 --- /dev/null +++ b/apps/VNLib.WebServer/src/Config/Validate.cs @@ -0,0 +1,113 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.WebServer +* File: Validate.cs +* +* Validate.cs is part of VNLib.WebServer which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.WebServer is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.WebServer 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.WebServer. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.Net; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +using VNLib.Utils.IO; + +namespace VNLib.WebServer.Config +{ + internal static class Validate + { + [DoesNotReturn] + public static void EnsureNotNull<T>(T? obj, string message) where T : class + { + if (obj is null) + { + throw new ServerConfigurationException(message); + } + + if (obj is string s && string.IsNullOrWhiteSpace(s)) + { + throw new ServerConfigurationException(message); + } + } + + public static void Assert([DoesNotReturnIf(false)] bool condition, string message) + { + if (!condition) + { + throw new ServerConfigurationException(message); + } + } + + public static void EnsureValidIp(string? address, string message) + { + if (!IPAddress.TryParse(address, out _)) + { + throw new ServerConfigurationException(message); + } + } + + public static void EnsureNotEqual<T>(T a, T b, string message) + { + if (a is null || b is null) + { + throw new ServerConfigurationException(message); + } + + if (a.Equals(b)) + { + throw new ServerConfigurationException(message); + } + } + + public static void EnsureRangeEx(ulong value, ulong min, ulong max, string message) + { + if (value < min || value > max) + { + throw new ServerConfigurationException(message); + } + } + + public static void EnsureRangeEx(long value, long min, long max, string message) + { + if (value < min || value > max) + { + throw new ServerConfigurationException(message); + } + } + + public static void EnsureRange(ulong value, ulong min, ulong max, [CallerArgumentExpression(nameof(value))] string? paramName = null) + { + EnsureRangeEx(value, min, max, $"Value for {paramName} must be between {min} and {max}. Value: {value}"); + } + + public static void EnsureRange(long value, long min, long max, [CallerArgumentExpression(nameof(value))] string? paramName = null) + { + EnsureRangeEx(value, min, max, $"Value for {paramName} must be between {min} and {max}. Value: {value}"); + } + + public static void FileExists(string path) + { + if (!FileOperations.FileExists(path)) + { + throw new ServerConfigurationException($"Required file: {path} not found"); + } + } + } +} |