From 8efd05c3a45eec155dca02b6038fd6d89e8042d8 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:12:02 +0000 Subject: [PATCH 1/4] Dev container config --- .devcontainer/devcontainer.json | 37 +++++++++++++++++++ .github/dependabot.yml | 12 ++++++ .../Titanium.Web.Proxy.csproj | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/dependabot.yml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..bd4f19ef --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,37 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "C# (.NET)", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm", + "features": { + "ghcr.io/devcontainers/features/dotnet:2": {} + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5000, 5001], + // "portsAttributes": { + // "5001": { + // "protocol": "https" + // } + // } + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "dotnet restore", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csdevkit", + "GitHub.copilot-chat" + ] + } + } + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..f33a02cd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for more information: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# https://containers.dev/guide/dependabot + +version: 2 +updates: + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj index 797580af..7a05bce3 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj @@ -24,7 +24,7 @@ 1701;1702;CA1416 - 1701;1702;CA1416;CS1591 + 1701;1702;CA1416 From b0bd107c22cb81f9631189cd2ac3d63af4ae06a8 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:17:34 +0000 Subject: [PATCH 2/4] chore: Enable Windows targetting to be able to restore on ubuntu --- .../Titanium.Web.Proxy.Examples.Basic.csproj | 1 + .../Titanium.Web.Proxy.Examples.WindowsService.csproj | 2 ++ .../Titanium.Web.Proxy.Examples.Wpf.csproj | 1 + 3 files changed, 4 insertions(+) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj index 7924f94c..ae88bbab 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj @@ -2,6 +2,7 @@ Exe net8.0 + true diff --git a/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj b/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj index d9379025..e9d4c9ba 100644 --- a/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj +++ b/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj @@ -19,6 +19,8 @@ 0 1.0.0.%2a false + + true win-x64 diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj index e9dbc810..57fc7df7 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj @@ -3,6 +3,7 @@ WinExe net8.0-windows true + true From 613e25a198f3dbf75f80668c9faf0b90a0d8af50 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:52:21 +0000 Subject: [PATCH 3/4] Docs: Document undocumented methods --- .../Certificates/CertificateManager.cs | 6 ++ .../EventArguments/SessionEventArgs.cs | 8 ++ .../EventArguments/TunnelConnectEventArgs.cs | 3 + src/Titanium.Web.Proxy/Helpers/RunTime.cs | 16 ++- .../Http/HeaderCollection.cs | 3 + src/Titanium.Web.Proxy/Http/KnownHeaders.cs | 100 +++++++++++++++++- .../Http/RequestResponseBase.cs | 3 + src/Titanium.Web.Proxy/Http/TunnelType.cs | 20 +++- .../Http2/Hpack/DynamicTable.cs | 3 + .../Http2/Hpack/HuffmanDecoder.cs | 9 +- .../Models/ExternalProxy.cs | 9 ++ src/Titanium.Web.Proxy/Models/HttpHeader.cs | 6 ++ .../Models/IExternalProxy.cs | 26 +++-- .../Models/ProxyAuthenticationContext.cs | 23 ++-- .../Models/ProxyProtocolType.cs | 7 +- .../Models/TransparentBaseProxyEndPoint.cs | 11 ++ .../Network/BufferPool/IBufferPool.cs | 20 +++- .../Network/Readers/IHttpStreamReader.cs | 30 ++++++ .../Network/Streams/ILineStream.cs | 23 +++- .../Network/Streams/IPeekStream.cs | 35 +++--- .../Network/Writers/IHttpStreamWriter.cs | 32 +++++- src/Titanium.Web.Proxy/ProxyServer.cs | 5 + .../WebSocket/WebSocketDecoder.cs | 13 ++- .../WebSocket/WebSocketFrame.cs | 23 ++++ .../WebSocket/WebsocketOpCode.cs | 27 +++++ 25 files changed, 417 insertions(+), 44 deletions(-) diff --git a/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs b/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs index 7769c7c0..f3dacfcf 100644 --- a/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs +++ b/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs @@ -24,6 +24,10 @@ public enum CertificateEngine /// BouncyCastle = 0, + /// + /// Uses BouncyCastle 3rd party library. + /// Observed to be faster than BouncyCastle. + /// BouncyCastleFast = 2, /// @@ -279,6 +283,7 @@ public ICertificateCache CertificateStorage /// public bool DisableWildCardCertificates { get; set; } = false; + /// public void Dispose() { Dispose(true); @@ -951,6 +956,7 @@ private void Dispose(bool disposing) disposed = true; } + /// ~CertificateManager() { Dispose(false); diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 682e534c..0e87a365 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -60,8 +60,14 @@ public bool ReRequest } } + /// + /// WebSocket decoder for sending data to server + /// public WebSocketDecoder WebSocketDecoderSend => webSocketDecoderSend ??= new WebSocketDecoder(BufferPool); + /// + /// WebSocket decoder for receiving data from server + /// public WebSocketDecoder WebSocketDecoderReceive => webSocketDecoderReceive ??= new WebSocketDecoder(BufferPool); /// @@ -611,6 +617,7 @@ public void TerminateServerConnection() HttpClient.CloseServerConnection = true; } + /// protected override void Dispose(bool disposing) { if (disposed) return; @@ -621,6 +628,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + /// ~SessionEventArgs() { #if DEBUG diff --git a/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs index b9b74989..7f3d73d3 100644 --- a/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs @@ -76,6 +76,9 @@ internal void OnDecryptedDataReceived(byte[] buffer, int offset, int count) } } + /// + /// Dispose the object. + /// ~TunnelConnectSessionEventArgs() { #if DEBUG diff --git a/src/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs index b528ff2c..30486acd 100644 --- a/src/Titanium.Web.Proxy/Helpers/RunTime.cs +++ b/src/Titanium.Web.Proxy/Helpers/RunTime.cs @@ -52,16 +52,30 @@ public static class RunTime #endif /// - /// Is running on Mono? + /// Is running on Mono? /// internal static bool IsRunningOnMono => isRunningOnMono.Value; + /// + /// Is running on Linux? + /// public static bool IsLinux => IsRunningOnLinux; + /// + /// Is running on Windows? + /// + /// Don't forget to also check public static bool IsWindows => IsRunningOnWindows; + /// + /// Is running on UWP on Windows? + /// + /// Don't forget to also check public static bool IsUwpOnWindows => IsWindows && UwpHelper.IsRunningAsUwp(); + /// + /// Is running on Mac? + /// public static bool IsMac => IsRunningOnMac; private static bool? _isSocketReuseAvailable; diff --git a/src/Titanium.Web.Proxy/Http/HeaderCollection.cs b/src/Titanium.Web.Proxy/Http/HeaderCollection.cs index a314023e..c3e9d6a1 100644 --- a/src/Titanium.Web.Proxy/Http/HeaderCollection.cs +++ b/src/Titanium.Web.Proxy/Http/HeaderCollection.cs @@ -84,6 +84,9 @@ public bool HeaderExists(string name) return null; } + /// + /// Gets the first header with given name if exists + /// public HttpHeader? GetFirstHeader(string name) { if (headers.TryGetValue(name, out var header)) return header; diff --git a/src/Titanium.Web.Proxy/Http/KnownHeaders.cs b/src/Titanium.Web.Proxy/Http/KnownHeaders.cs index 3c385e5a..8e6a9578 100644 --- a/src/Titanium.Web.Proxy/Http/KnownHeaders.cs +++ b/src/Titanium.Web.Proxy/Http/KnownHeaders.cs @@ -1,51 +1,143 @@ namespace Titanium.Web.Proxy.Http; /// -/// Well known http headers. +/// The KnownHeaders class provides static instances of known HTTP headers. +/// These instances can be used to avoid the overhead of creating new strings for common headers. /// public static class KnownHeaders { - // Both + /// + /// The 'Connection' HTTP header. + /// public static KnownHeader Connection = "Connection"; + + /// + /// The 'close' value for the 'Connection' HTTP header. + /// public static KnownHeader ConnectionClose = "close"; + + /// + /// The 'keep-alive' value for the 'Connection' HTTP header. + /// public static KnownHeader ConnectionKeepAlive = "keep-alive"; + /// + /// The 'Content-Length' HTTP header. + /// public static KnownHeader ContentLength = "Content-Length"; + + /// + /// The 'content-length' HTTP header for HTTP/2. + /// public static KnownHeader ContentLengthHttp2 = "content-length"; + /// + /// The 'Content-Type' HTTP header. + /// public static KnownHeader ContentType = "Content-Type"; + + /// + /// The 'charset' value for the 'Content-Type' HTTP header. + /// public static KnownHeader ContentTypeCharset = "charset"; + + /// + /// The 'boundary' value for the 'Content-Type' HTTP header. + /// public static KnownHeader ContentTypeBoundary = "boundary"; + /// + /// The 'Upgrade' HTTP header. + /// public static KnownHeader Upgrade = "Upgrade"; + + /// + /// The 'websocket' value for the 'Upgrade' HTTP header. + /// public static KnownHeader UpgradeWebsocket = "websocket"; - // Request headers + /// + /// The 'Accept-Encoding' HTTP header. + /// public static KnownHeader AcceptEncoding = "Accept-Encoding"; + /// + /// The 'Authorization' HTTP header. + /// public static KnownHeader Authorization = "Authorization"; + /// + /// The 'Expect' HTTP header. + /// public static KnownHeader Expect = "Expect"; + + /// + /// The '100-continue' expectation for the 'Expect' HTTP header. + /// public static KnownHeader Expect100Continue = "100-continue"; + /// + /// The 'Host' HTTP header. + /// public static KnownHeader Host = "Host"; + /// + /// The 'Proxy-Authorization' HTTP header. + /// public static KnownHeader ProxyAuthorization = "Proxy-Authorization"; + + /// + /// The 'basic' value for the 'Proxy-Authorization' HTTP header. + /// public static KnownHeader ProxyAuthorizationBasic = "basic"; + /// + /// The 'Proxy-Connection' HTTP header. + /// public static KnownHeader ProxyConnection = "Proxy-Connection"; + + /// + /// The 'close' value for the 'Proxy-Connection' HTTP header. + /// public static KnownHeader ProxyConnectionClose = "close"; - // Response headers + /// + /// The 'Content-Encoding' HTTP header. + /// public static KnownHeader ContentEncoding = "Content-Encoding"; + + /// + /// The 'deflate' value for the 'Content-Encoding' HTTP header. + /// public static KnownHeader ContentEncodingDeflate = "deflate"; + + /// + /// The 'gzip' value for the 'Content-Encoding' HTTP header. + /// public static KnownHeader ContentEncodingGzip = "gzip"; + + /// + /// The 'br' (Brotli) value for the 'Content-Encoding' HTTP header. + /// public static KnownHeader ContentEncodingBrotli = "br"; + /// + /// The 'Location' HTTP header. + /// public static KnownHeader Location = "Location"; + /// + /// The 'Proxy-Authenticate' HTTP header. + /// public static KnownHeader ProxyAuthenticate = "Proxy-Authenticate"; + /// + /// The 'Transfer-Encoding' HTTP header. + /// public static KnownHeader TransferEncoding = "Transfer-Encoding"; + + /// + /// The 'chunked' value for the 'Transfer-Encoding' HTTP header. + /// public static KnownHeader TransferEncodingChunked = "chunked"; } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs b/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs index 4b785abb..46aad491 100644 --- a/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs +++ b/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs @@ -300,6 +300,9 @@ internal void FinishSession() } } + /// + /// HeaderText as string + /// public override string ToString() { return HeaderText; diff --git a/src/Titanium.Web.Proxy/Http/TunnelType.cs b/src/Titanium.Web.Proxy/Http/TunnelType.cs index c000a0bd..914ba82f 100644 --- a/src/Titanium.Web.Proxy/Http/TunnelType.cs +++ b/src/Titanium.Web.Proxy/Http/TunnelType.cs @@ -1,9 +1,27 @@ namespace Titanium.Web.Proxy.Http; +/// +/// The TunnelType enumeration represents the type of tunnel used in a proxy connection. +/// public enum TunnelType { + /// + /// The tunnel type is unknown. + /// Unknown, + + /// + /// The tunnel is used for HTTPS connections. + /// Https, + + /// + /// The tunnel is used for WebSocket connections. + /// Websocket, + + /// + /// The tunnel is used for HTTP/2 connections. + /// Http2 -} \ No newline at end of file +} diff --git a/src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs b/src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs index 7c9c94dc..6779e3d1 100644 --- a/src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs +++ b/src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs @@ -20,6 +20,9 @@ namespace Titanium.Web.Proxy.Http2.Hpack; +/// +/// A dynamic table of header fields. +/// public class DynamicTable { // a circular queue of header fields diff --git a/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs b/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs index 3a0566b3..959293b5 100644 --- a/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs +++ b/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs @@ -19,7 +19,14 @@ using System.IO; namespace Titanium.Web.Proxy.Http2.Hpack; - +/// +/// The HuffmanDecoder class is responsible for decoding Huffman encoded data. +/// It uses a Huffman tree built from predefined Huffman codes and lengths. +/// The decoding process involves traversing the Huffman tree based on the input data, +/// and outputting the symbol when a terminal node is reached. +/// This class is designed to be used in the context of HPACK (Header Compression for HTTP/2), +/// where Huffman coding is used to compress HTTP headers. +/// public class HuffmanDecoder { /// diff --git a/src/Titanium.Web.Proxy/Models/ExternalProxy.cs b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs index 880e87ac..2fa4f6b2 100644 --- a/src/Titanium.Web.Proxy/Models/ExternalProxy.cs +++ b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs @@ -58,8 +58,14 @@ public ExternalProxy(string hostName, int port, string userName, string password /// public bool BypassLocalhost { get; set; } + /// + /// Proxy type. + /// public ExternalProxyType ProxyType { get; set; } + /// + /// Should DNS requests be proxied? + /// public bool ProxyDnsRequests { get; set; } /// @@ -110,6 +116,9 @@ public override string ToString() } } +/// +/// Type of external proxy server. +/// public enum ExternalProxyType { /// A HTTP/HTTPS proxy server. diff --git a/src/Titanium.Web.Proxy/Models/HttpHeader.cs b/src/Titanium.Web.Proxy/Models/HttpHeader.cs index e2374aef..da788a24 100644 --- a/src/Titanium.Web.Proxy/Models/HttpHeader.cs +++ b/src/Titanium.Web.Proxy/Models/HttpHeader.cs @@ -36,6 +36,9 @@ public class HttpHeader internal static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ISO-8859-1"); + /// + /// Default encoding used in headers. + /// public static Encoding Encoding => DefaultEncoding; internal static readonly HttpHeader ProxyConnectionKeepAlive = new("Proxy-Connection", "keep-alive"); @@ -107,6 +110,9 @@ private protected HttpHeader(ByteString name, ByteString value, bool headerEntry internal ByteString ValueData { get; private set; } + /// + /// Header Size. + /// public int Size => Name.Length + Value.Length + HttpHeaderOverhead; internal static int SizeOf(ByteString name, ByteString value) diff --git a/src/Titanium.Web.Proxy/Models/IExternalProxy.cs b/src/Titanium.Web.Proxy/Models/IExternalProxy.cs index b91a9cae..26af7cc4 100644 --- a/src/Titanium.Web.Proxy/Models/IExternalProxy.cs +++ b/src/Titanium.Web.Proxy/Models/IExternalProxy.cs @@ -1,40 +1,54 @@ namespace Titanium.Web.Proxy.Models; +/// +/// The IExternalProxy interface defines the contract for an external proxy. +/// It provides properties for configuring the proxy's credentials, host, port, and other settings. +/// public interface IExternalProxy { /// - /// Use default windows credentials? + /// Gets or sets a value indicating whether to use default windows credentials. /// bool UseDefaultCredentials { get; set; } /// - /// Bypass this proxy for connections to localhost? + /// Gets or sets a value indicating whether to bypass this proxy for connections to localhost. /// bool BypassLocalhost { get; set; } + /// + /// Gets or sets the type of the external proxy. + /// ExternalProxyType ProxyType { get; set; } + /// + /// Gets or sets a value indicating whether to proxy DNS requests. + /// bool ProxyDnsRequests { get; set; } /// - /// Username. + /// Gets or sets the username for the proxy. /// string? UserName { get; set; } /// - /// Password. + /// Gets or sets the password for the proxy. /// string? Password { get; set; } /// - /// Host name. + /// Gets or sets the host name of the proxy. /// string HostName { get; set; } /// - /// Port. + /// Gets or sets the port number of the proxy. /// int Port { get; set; } + /// + /// Returns a string that represents the current object. + /// + /// A string that represents the current object. string ToString(); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs b/src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs index a34491bc..ea3b11c1 100644 --- a/src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs +++ b/src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs @@ -1,26 +1,29 @@ namespace Titanium.Web.Proxy.Models; - +/// +/// The ProxyAuthenticationResult enumeration represents the possible results of a proxy authentication attempt. +/// It provides values for indicating success, failure due to invalid credentials, and other potential outcomes. +/// public enum ProxyAuthenticationResult { /// - /// Indicates the authentication request was successful + /// Indicates the authentication request was successful. /// Success, /// - /// Indicates the authentication request failed + /// Indicates the authentication request failed. /// Failure, /// - /// Indicates that this stage of the authentication request succeeded - /// And a second pass of the handshake needs to occur + /// Indicates that this stage of the authentication request succeeded + /// And a second pass of the handshake needs to occur /// ContinuationNeeded } /// -/// A context container for authentication flows +/// A context container for authentication flows /// public class ProxyAuthenticationContext { @@ -34,6 +37,10 @@ public class ProxyAuthenticationContext /// public string? Continuation { get; set; } + /// + /// Creates a new ProxyAuthenticationContext instance representing a failed authentication attempt. + /// + /// A new ProxyAuthenticationContext instance with Result set to Failure and Continuation set to null. public static ProxyAuthenticationContext Failed() { return new ProxyAuthenticationContext @@ -43,6 +50,10 @@ public static ProxyAuthenticationContext Failed() }; } + /// + /// Creates a new ProxyAuthenticationContext instance representing a successful authentication attempt. + /// + /// A new ProxyAuthenticationContext instance with Result set to Success and Continuation set to null. public static ProxyAuthenticationContext Succeeded() { return new ProxyAuthenticationContext diff --git a/src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs b/src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs index a292321e..c6ddb137 100644 --- a/src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs +++ b/src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs @@ -1,7 +1,12 @@ using System; namespace Titanium.Web.Proxy.Models; - +/// +/// The ProxyProtocolType enumeration represents the types of protocols that a proxy can support. +/// It is a flags enumeration, which means multiple values can be combined using bitwise operations. +/// The values include None (indicating no protocol), Http (for HTTP protocol), Https (for HTTPS protocol), +/// and AllHttp (for both HTTP and HTTPS protocols). +/// [Flags] public enum ProxyProtocolType { diff --git a/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs index f8bddc32..fe6fe4d6 100644 --- a/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs +++ b/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs @@ -4,8 +4,19 @@ namespace Titanium.Web.Proxy.Models; +/// +/// The TransparentBaseProxyEndPoint class is an abstract base class for endpoints that support transparent proxying. +/// It inherits from the ProxyEndPoint class and provides additional functionality specific to transparent proxying, +/// such as SSL decryption and handling of SSL authentication. +/// public abstract class TransparentBaseProxyEndPoint : ProxyEndPoint { + /// + /// Initializes a new instance of the TransparentBaseProxyEndPoint class with the specified IP address, port, and SSL decryption setting. + /// + /// The IP address of the endpoint. + /// The port of the endpoint. + /// A boolean value that indicates whether SSL decryption is enabled for this endpoint. protected TransparentBaseProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl) : base(ipAddress, port, decryptSsl) { diff --git a/src/Titanium.Web.Proxy/Network/BufferPool/IBufferPool.cs b/src/Titanium.Web.Proxy/Network/BufferPool/IBufferPool.cs index f09b19de..f56b465f 100644 --- a/src/Titanium.Web.Proxy/Network/BufferPool/IBufferPool.cs +++ b/src/Titanium.Web.Proxy/Network/BufferPool/IBufferPool.cs @@ -3,16 +3,32 @@ namespace Titanium.Web.Proxy.StreamExtended.BufferPool; /// -/// Use this interface to implement custom buffer pool. -/// To use the default buffer pool implementation use DefaultBufferPool class. +/// The IBufferPool interface defines the contract for a custom buffer pool. +/// To use the default buffer pool implementation, use the DefaultBufferPool class. /// public interface IBufferPool : IDisposable { + /// + /// Gets the size of the buffer. + /// int BufferSize { get; } + /// + /// Retrieves a buffer from the pool. + /// + /// A byte array representing the buffer. byte[] GetBuffer(); + /// + /// Retrieves a buffer of a specific size from the pool. + /// + /// The size of the buffer to retrieve. + /// A byte array representing the buffer. byte[] GetBuffer(int bufferSize); + /// + /// Returns a buffer to the pool. + /// + /// The buffer to return to the pool. void ReturnBuffer(byte[] buffer); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Network/Readers/IHttpStreamReader.cs b/src/Titanium.Web.Proxy/Network/Readers/IHttpStreamReader.cs index 306c2a20..9963ccbb 100644 --- a/src/Titanium.Web.Proxy/Network/Readers/IHttpStreamReader.cs +++ b/src/Titanium.Web.Proxy/Network/Readers/IHttpStreamReader.cs @@ -4,12 +4,42 @@ namespace Titanium.Web.Proxy.StreamExtended.Network; +/// +/// The IHttpStreamReader interface defines the contract for a reader that can read HTTP data from a stream. +/// It provides methods for reading bytes and copying the body of an HTTP message, either synchronously or asynchronously. +/// This interface is designed to be used in the context of network streams, where data is often read in a line-by-line manner. +/// public interface IHttpStreamReader : ILineStream { + /// + /// Reads a sequence of bytes from the stream. + /// + /// The buffer to write data into. + /// The zero-based byte offset in buffer at which to begin storing the data read from the stream. + /// The maximum number of bytes to be read from the stream. + /// The total number of bytes read into the buffer. int Read(byte[] buffer, int offset, int count); + /// + /// Asynchronously reads a sequence of bytes from the stream. + /// + /// The buffer to write data into. + /// The zero-based byte offset in buffer at which to begin storing the data read from the stream. + /// The maximum number of bytes to be read from the stream. + /// A CancellationToken to observe while waiting for the task to complete. + /// A Task that represents the asynchronous read operation. The value of the TResult parameter contains the total number of bytes read into the buffer. Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); + /// + /// Asynchronously copies the body of an HTTP message to a writer. + /// + /// The IHttpStreamWriter to which the body should be copied. + /// A boolean value indicating whether the body is chunked. + /// The length of the content to be copied. + /// A boolean value indicating whether the body is a request. + /// The SessionEventArgs associated with the HTTP session. + /// A CancellationToken to observe while waiting for the task to complete. + /// A Task that represents the asynchronous copy operation. Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Network/Streams/ILineStream.cs b/src/Titanium.Web.Proxy/Network/Streams/ILineStream.cs index 6d8eee36..c3a1414c 100644 --- a/src/Titanium.Web.Proxy/Network/Streams/ILineStream.cs +++ b/src/Titanium.Web.Proxy/Network/Streams/ILineStream.cs @@ -2,22 +2,35 @@ using System.Threading.Tasks; namespace Titanium.Web.Proxy.StreamExtended.Network; - +/// +/// The ILineStream interface defines the contract for a stream that supports line-by-line reading of data. +/// It provides methods for filling a buffer asynchronously, reading a byte from the buffer, and reading a line asynchronously. +/// This interface is designed to be used in the context of network streams, where data is often read in a line-by-line manner. +/// public interface ILineStream { + /// + /// Gets a value indicating whether data is available in the internal buffer. + /// bool DataAvailable { get; } /// - /// Fills the buffer asynchronous. + /// Asynchronously fills the internal buffer with data from the stream. /// - /// + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that completes when the buffer has been filled, yielding a boolean indicating whether any data was read. ValueTask FillBufferAsync(CancellationToken cancellationToken = default); + /// + /// Reads a single byte from the internal buffer. + /// + /// The byte read from the buffer. byte ReadByteFromBuffer(); /// - /// Read a line from the byte stream + /// Asynchronously reads a line of data from the stream. /// - /// + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that completes when the line has been read, yielding the line as a string, or null if the end of the stream has been reached. ValueTask ReadLineAsync(CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Network/Streams/IPeekStream.cs b/src/Titanium.Web.Proxy/Network/Streams/IPeekStream.cs index 0c2e5159..41313913 100644 --- a/src/Titanium.Web.Proxy/Network/Streams/IPeekStream.cs +++ b/src/Titanium.Web.Proxy/Network/Streams/IPeekStream.cs @@ -4,33 +4,38 @@ namespace Titanium.Web.Proxy.StreamExtended.Network; +/// +/// The IPeekStream interface defines the contract for a stream that supports peeking at its data without consuming it. +/// It provides methods for peeking at a single byte or multiple bytes, either synchronously or asynchronously. +/// This interface is designed to be used in the context of network streams, where it is often necessary to look ahead in the data without consuming it. +/// public interface IPeekStream { /// - /// Peeks a byte from buffer. + /// Peeks at a single byte from the buffer at the specified index. /// - /// The index. - /// - /// Index is out of buffer size + /// The index in the buffer to peek at. + /// The byte at the specified index in the buffer. + /// Thrown when the index is out of the buffer size. byte PeekByteFromBuffer(int index); /// - /// Peeks a byte asynchronous. + /// Asynchronously peeks at a single byte from the buffer at the specified index. /// - /// The index. - /// The cancellation token. - /// + /// The index in the buffer to peek at. + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that completes when the byte has been peeked, yielding the byte as an integer. ValueTask PeekByteAsync(int index, CancellationToken cancellationToken = default); /// - /// Peeks bytes asynchronous. + /// Asynchronously peeks at multiple bytes from the buffer, copying them into the provided buffer. /// - /// The buffer to copy. - /// The offset where copying. - /// The index. - /// The count. - /// The cancellation token. - /// + /// The buffer to copy the bytes into. + /// The offset in the destination buffer at which to start copying. + /// The index in the source buffer at which to start peeking. + /// The number of bytes to peek. + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that completes when the bytes have been peeked, yielding the number of bytes peeked as an integer. ValueTask PeekBytesAsync(byte[] buffer, int offset, int index, int count, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Network/Writers/IHttpStreamWriter.cs b/src/Titanium.Web.Proxy/Network/Writers/IHttpStreamWriter.cs index 65b43aa2..6038fe67 100644 --- a/src/Titanium.Web.Proxy/Network/Writers/IHttpStreamWriter.cs +++ b/src/Titanium.Web.Proxy/Network/Writers/IHttpStreamWriter.cs @@ -4,17 +4,47 @@ namespace Titanium.Web.Proxy.StreamExtended.Network; /// -/// A concrete implementation of this interface is required when calling CopyStream. +/// The IHttpStreamWriter interface defines the contract for a writer that can write HTTP data to a stream. +/// It provides methods for writing bytes, writing a line, and writing a line with a specified value, either synchronously or asynchronously. +/// This interface is designed to be used in the context of network streams, where data is often written in a line-by-line manner. /// public interface IHttpStreamWriter { + /// + /// Gets a value indicating whether the underlying stream is a network stream. + /// bool IsNetworkStream { get; } + /// + /// Writes a sequence of bytes to the stream. + /// + /// The buffer to write data from. + /// The zero-based byte offset in buffer at which to begin copying bytes to the stream. + /// The number of bytes to be written to the stream. void Write(byte[] buffer, int offset, int count); + /// + /// Asynchronously writes a sequence of bytes to the stream. + /// + /// The buffer to write data from. + /// The zero-based byte offset in buffer at which to begin copying bytes to the stream. + /// The number of bytes to be written to the stream. + /// A CancellationToken to observe while waiting for the task to complete. + /// A Task that represents the asynchronous write operation. Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); + /// + /// Asynchronously writes a newline character to the stream. + /// + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that represents the asynchronous write operation. ValueTask WriteLineAsync(CancellationToken cancellationToken = default); + /// + /// Asynchronously writes a string followed by a newline character to the stream. + /// + /// The string to write to the stream. + /// A CancellationToken to observe while waiting for the task to complete. + /// A ValueTask that represents the asynchronous write operation. ValueTask WriteLineAsync(string value, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index 08d37152..b897a320 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -941,6 +941,9 @@ private void ThrowNotSupportedException([CallerMemberName]string? caller = null) private bool disposed; + /// + /// Dispose the ProxyServer instance, and stop the proxy server if running. + /// protected virtual void Dispose(bool disposing) { if (disposed) return; @@ -966,12 +969,14 @@ protected virtual void Dispose(bool disposing) } } + /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + /// ~ProxyServer() { Dispose(false); diff --git a/src/Titanium.Web.Proxy/WebSocket/WebSocketDecoder.cs b/src/Titanium.Web.Proxy/WebSocket/WebSocketDecoder.cs index 99e9282c..6c6af581 100644 --- a/src/Titanium.Web.Proxy/WebSocket/WebSocketDecoder.cs +++ b/src/Titanium.Web.Proxy/WebSocket/WebSocketDecoder.cs @@ -4,7 +4,11 @@ using Titanium.Web.Proxy.StreamExtended.BufferPool; namespace Titanium.Web.Proxy; - +/// +/// The WebSocketDecoder class is responsible for decoding WebSocket frames from a stream of bytes. +/// It uses a buffer to store incoming data and decodes frames from this buffer as they become available. +/// This class is designed to be used in the context of a WebSocket connection, where frames are used to send and receive data. +/// public class WebSocketDecoder { private byte[] buffer; @@ -16,6 +20,13 @@ internal WebSocketDecoder(IBufferPool bufferPool) buffer = new byte[bufferPool.BufferSize]; } + /// + /// Decodes WebSocket frames from the provided data. + /// + /// The data to decode frames from. + /// The offset in the data at which to start decoding. + /// The number of bytes in the data to decode. + /// An IEnumerable of WebSocketFrame representing the decoded frames. public IEnumerable Decode(byte[] data, int offset, int count) { var buffer = data.AsMemory(offset, count); diff --git a/src/Titanium.Web.Proxy/WebSocket/WebSocketFrame.cs b/src/Titanium.Web.Proxy/WebSocket/WebSocketFrame.cs index 329163e5..00edbc81 100644 --- a/src/Titanium.Web.Proxy/WebSocket/WebSocketFrame.cs +++ b/src/Titanium.Web.Proxy/WebSocket/WebSocketFrame.cs @@ -3,19 +3,42 @@ namespace Titanium.Web.Proxy; +/// +/// The WebSocketFrame class represents a single frame of data in a WebSocket connection. +/// It provides properties for accessing the finality, operation code, and data of the frame, +/// as well as methods for getting the data as a text string. +/// public class WebSocketFrame { + /// + /// Gets a value indicating whether this frame is the final frame in a message. + /// public bool IsFinal { get; internal set; } + /// + /// Gets the operation code for this frame, which indicates the type of data contained in the frame. + /// public WebsocketOpCode OpCode { get; internal set; } + /// + /// Gets the data contained in this frame as a read-only memory of bytes. + /// public ReadOnlyMemory Data { get; internal set; } + /// + /// Gets the data contained in this frame as a text string, using UTF-8 encoding. + /// + /// The data as a text string. public string GetText() { return GetText(Encoding.UTF8); } + /// + /// Gets the data contained in this frame as a text string, using the specified encoding. + /// + /// The encoding to use when converting the data to a string. + /// The data as a text string. public string GetText(Encoding encoding) { #if NET6_0_OR_GREATER diff --git a/src/Titanium.Web.Proxy/WebSocket/WebsocketOpCode.cs b/src/Titanium.Web.Proxy/WebSocket/WebsocketOpCode.cs index bb61f6f9..56b75a2f 100644 --- a/src/Titanium.Web.Proxy/WebSocket/WebsocketOpCode.cs +++ b/src/Titanium.Web.Proxy/WebSocket/WebsocketOpCode.cs @@ -1,11 +1,38 @@ namespace Titanium.Web.Proxy; +/// +/// The WebsocketOpCode enumeration represents the operation codes for WebSocket frames. +/// These codes are used to indicate the type of data contained in a WebSocket message frame. +/// public enum WebsocketOpCode : byte { + /// + /// Indicates a continuation frame. + /// Continuation, + + /// + /// Indicates a text frame. + /// Text, + + /// + /// Indicates a binary frame. + /// Binary, + + /// + /// Indicates a connection close frame. + /// ConnectionClose = 8, + + /// + /// Indicates a ping frame. + /// Ping, + + /// + /// Indicates a pong frame. + /// Pong } \ No newline at end of file From e3403c48531228d5205cba1d3fad35b621de15c8 Mon Sep 17 00:00:00 2001 From: Stephan van Rooij <1292510+svrooij@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:28:26 +0000 Subject: [PATCH 4/4] docs: A whole lot of additional public types documented --- .../Makers/WinCertificateMaker.cs | 132 ++++++++++++++++++ .../EventArguments/SessionEventArgsBase.cs | 42 +++++- .../Http2/Hpack/HpackUtil.cs | 31 +++- .../Network/Models/TaskResult.cs | 46 +++++- .../Network/Ssl/ClientHelloInfo.cs | 48 ++++++- .../Network/Ssl/ServerHelloInfo.cs | 46 +++++- .../Network/Ssl/SslTools.cs | 2 +- 7 files changed, 329 insertions(+), 18 deletions(-) diff --git a/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs b/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs index dc346869..8af7d161 100644 --- a/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs +++ b/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs @@ -305,42 +305,174 @@ private X509Certificate2 MakeCertificate(string subject, string fullSubject, #pragma warning restore +/// +/// The EncodingType enumeration represents the different encoding types that can be used when creating a certificate. +/// public enum EncodingType { + /// + /// Represents any encoding type. + /// XcnCryptStringAny = 7, + + /// + /// Represents Base64 encoding. + /// XcnCryptStringBase64 = 1, + + /// + /// Represents any Base64 encoding. + /// XcnCryptStringBase64Any = 6, + + /// + /// Represents Base64 encoding with a header. + /// XcnCryptStringBase64Header = 0, + + /// + /// Represents Base64 encoding with a request header. + /// XcnCryptStringBase64Requestheader = 3, + + /// + /// Represents Base64 encoding for URIs. + /// XcnCryptStringBase64Uri = 13, + + /// + /// Represents Base64 encoding with a X509 CRL header. + /// XcnCryptStringBase64X509Crlheader = 9, + + /// + /// Represents binary encoding. + /// XcnCryptStringBinary = 2, + + /// + /// Represents chain encoding. + /// XcnCryptStringChain = 0x100, + + /// + /// Represents the encode mask. + /// XcnCryptStringEncodemask = 0xff, + + /// + /// Represents hash data encoding. + /// XcnCryptStringHashdata = 0x10000000, + + /// + /// Represents hexadecimal encoding. + /// XcnCryptStringHex = 4, + + /// + /// Represents any hexadecimal encoding. + /// XcnCryptStringHexAny = 8, + + /// + /// Represents hexadecimal address encoding. + /// XcnCryptStringHexaddr = 10, + + /// + /// Represents hexadecimal ASCII encoding. + /// XcnCryptStringHexascii = 5, + + /// + /// Represents hexadecimal ASCII address encoding. + /// XcnCryptStringHexasciiaddr = 11, + + /// + /// Represents raw hexadecimal encoding. + /// XcnCryptStringHexraw = 12, + + /// + /// Represents encoding with no carriage return. + /// XcnCryptStringNocr = -2147483648, + + /// + /// Represents encoding with no CRLF. + /// XcnCryptStringNocrlf = 0x40000000, + + /// + /// Represents percent escape encoding. + /// XcnCryptStringPercentescape = 0x8000000, + + /// + /// Represents strict encoding. + /// XcnCryptStringStrict = 0x20000000, + + /// + /// Represents text encoding. + /// XcnCryptStringText = 0x200 } +/// +/// The AlternativeNameType enumeration represents the different types of alternative names that can be used in a certificate. +/// public enum AlternativeNameType { + /// + /// Represents a directory name. + /// XcnCertAltNameDirectoryName = 5, + + /// + /// Represents a DNS name. + /// XcnCertAltNameDnsName = 3, + + /// + /// Represents a GUID. + /// XcnCertAltNameGuid = 10, + + /// + /// Represents an IP address. + /// XcnCertAltNameIpAddress = 8, + + /// + /// Represents an other name. + /// XcnCertAltNameOtherName = 1, + + /// + /// Represents a registered ID. + /// XcnCertAltNameRegisteredId = 9, + + /// + /// Represents an RFC 822 name. + /// XcnCertAltNameRfc822Name = 2, + + /// + /// Represents an unknown name type. + /// XcnCertAltNameUnknown = 0, + + /// + /// Represents a URL. + /// XcnCertAltNameUrl = 7, + + /// + /// Represents a user principle name. + /// XcnCertAltNameUserPrincipleName = 11 } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs index dba34e4d..0bbc8473 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs @@ -13,24 +13,38 @@ namespace Titanium.Web.Proxy.EventArguments; /// -/// Holds info related to a single proxy session (single request/response sequence). -/// A proxy session is bounded to a single connection from client. -/// A proxy session ends when client terminates connection to proxy -/// or when server terminates connection from proxy. +/// Holds info related to a single proxy session (single request/response sequence). +/// A proxy session is bounded to a single connection from client. +/// A proxy session ends when client terminates connection to proxy +/// or when server terminates connection from proxy. /// public abstract class SessionEventArgsBase : ProxyEventArgsBase, IDisposable { + /// + /// Buffer pool used for the session. + /// protected readonly IBufferPool BufferPool; + /// + /// Cancellation token source for the session. + /// internal readonly CancellationTokenSource CancellationTokenSource; + + /// + /// Exception handler function for the session. + /// protected readonly ExceptionHandler? ExceptionFunc; + + /// + /// Logger instance for the session. + /// internal readonly ILogger logger; private bool disposed; private bool enableWinAuth; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint, HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, @@ -61,8 +75,14 @@ private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoin internal HttpClientStream ClientStream { get; } + /// + /// Unique identifier of this session, on the client side. + /// public Guid ClientConnectionId => ClientConnection.Id; + /// + /// Unique identifier of this session, on the server side. + /// public Guid ServerConnectionId => HttpClient.HasConnection ? ServerConnection.Id : Guid.Empty; /// @@ -154,17 +174,26 @@ public bool EnableWinAuth /// public Exception? Exception { get; internal set; } + /// + /// Dispose this instance. + /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + /// + /// Called when an exception is thrown in user event. + /// protected void OnException(Exception exception) { ExceptionFunc?.Invoke(exception); } + /// + /// Dispose this instance. + /// protected virtual void Dispose(bool disposing) { if (disposed) return; @@ -183,6 +212,9 @@ protected virtual void Dispose(bool disposing) disposed = true; } + /// + /// Finalizer. + /// ~SessionEventArgsBase() { #if DEBUG diff --git a/src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs b/src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs index ec0d2a10..40c3d411 100644 --- a/src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs +++ b/src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs @@ -17,20 +17,35 @@ namespace Titanium.Web.Proxy.Http2.Hpack; +/// +/// HPACK util +/// public static class HpackUtil { - // Section 6.2. Literal Header Field Representation + /// + /// Section 6.2. Literal Header Field Representation + /// http://tools.ietf.org/html/rfc7541#section-6.2 + /// public enum IndexType { - Incremental, // Section 6.2.1. Literal Header Field with Incremental Indexing - None, // Section 6.2.2. Literal Header Field without Indexing - Never // Section 6.2.3. Literal Header Field never Indexed + /// Section 6.2.1. Literal Header Field with Incremental Indexing + Incremental, + /// Section 6.2.2. Literal Header Field without Indexing + None, + /// Section 6.2.3. Literal Header Field never Indexed + Never } + /// + /// Section 6.1. Indexed Header Field Representation + /// http://tools.ietf.org/html/rfc7541#section-6.1 + /// public const int HuffmanEos = 256; - // Appendix B: Huffman Codes - // http://tools.ietf.org/html/rfc7541#appendix-B + /// + /// Appendix B: Huffman Codes + /// http://tools.ietf.org/html/rfc7541#appendix-B + /// public static readonly int[] HuffmanCodes = { 0x1ff8, @@ -292,6 +307,10 @@ public enum IndexType 0x3fffffff // EOS }; + /// + /// The HuffmanCodeLengths array represents the lengths of the Huffman codes used in HPACK, the header compression format for HTTP/2. + /// The array contains 257 entries, one for each 8-bit symbol and an additional one for the EOS (end-of-string) symbol. + /// public static readonly byte[] HuffmanCodeLengths = { 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, diff --git a/src/Titanium.Web.Proxy/Network/Models/TaskResult.cs b/src/Titanium.Web.Proxy/Network/Models/TaskResult.cs index 783930bf..fd0d11af 100644 --- a/src/Titanium.Web.Proxy/Network/Models/TaskResult.cs +++ b/src/Titanium.Web.Proxy/Network/Models/TaskResult.cs @@ -5,26 +5,46 @@ namespace Titanium.Web.Proxy.StreamExtended.Network; /// -/// Mimic a Task but you can set AsyncState +/// Mimics a Task but allows setting of AsyncState. /// public class TaskResult : IAsyncResult { private readonly Task task; + /// + /// Initializes a new instance of the class. + /// + /// The task to be wrapped. + /// The state object to be associated with the task. public TaskResult(Task pTask, object state) { task = pTask; AsyncState = state; } + /// + /// Gets the state object associated with this task. + /// public object AsyncState { get; } + /// + /// Gets a WaitHandle that is used to wait for the task to complete. + /// public WaitHandle AsyncWaitHandle => ((IAsyncResult)task).AsyncWaitHandle; + /// + /// Gets a value indicating whether the task completed synchronously. + /// public bool CompletedSynchronously => ((IAsyncResult)task).CompletedSynchronously; + /// + /// Gets a value indicating whether the task has completed. + /// public bool IsCompleted => task.IsCompleted; + /// + /// Blocks the calling thread until the task completes. + /// public void GetResult() { task.GetAwaiter().GetResult(); @@ -32,26 +52,46 @@ public void GetResult() } /// -/// Mimic a Task<T> but you can set AsyncState +/// Mimics a Task<T> but allows setting of AsyncState. /// -/// +/// The type of the result produced by the task. public class TaskResult : IAsyncResult { private readonly Task task; + /// + /// Initializes a new instance of the class. + /// + /// The task to be wrapped. + /// The state object to be associated with the task. public TaskResult(Task pTask, object state) { task = pTask; AsyncState = state; } + /// + /// Gets the result value of the task. + /// public T Result => task.Result; + /// + /// Gets the state object associated with this task. + /// public object AsyncState { get; } + /// + /// Gets a WaitHandle that is used to wait for the task to complete. + /// public WaitHandle AsyncWaitHandle => ((IAsyncResult)task).AsyncWaitHandle; + /// + /// Gets a value indicating whether the task completed synchronously. + /// public bool CompletedSynchronously => ((IAsyncResult)task).CompletedSynchronously; + /// + /// Gets a value indicating whether the task has completed. + /// public bool IsCompleted => task.IsCompleted; } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Network/Ssl/ClientHelloInfo.cs b/src/Titanium.Web.Proxy/Network/Ssl/ClientHelloInfo.cs index 4971e1dc..a009af38 100644 --- a/src/Titanium.Web.Proxy/Network/Ssl/ClientHelloInfo.cs +++ b/src/Titanium.Web.Proxy/Network/Ssl/ClientHelloInfo.cs @@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.StreamExtended; /// -/// Wraps up the client SSL hello information. +/// Represents the client SSL hello information. /// public class ClientHelloInfo { @@ -20,6 +20,16 @@ public class ClientHelloInfo "DEFLATE" }; + /// + /// Initializes a new instance of the class. + /// + /// The handshake version. + /// The major version. + /// The minor version. + /// The random bytes. + /// The session ID. + /// The ciphers. + /// The length of the client hello message. internal ClientHelloInfo(int handshakeVersion, int majorVersion, int minorVersion, byte[] random, byte[] sessionId, int[] ciphers, int clientHelloLength) { @@ -32,14 +42,29 @@ internal ClientHelloInfo(int handshakeVersion, int majorVersion, int minorVersio ClientHelloLength = clientHelloLength; } + /// + /// Gets the handshake version. + /// public int HandshakeVersion { get; } + /// + /// Gets the major version. + /// public int MajorVersion { get; } + /// + /// Gets the minor version. + /// public int MinorVersion { get; } + /// + /// Gets the random bytes. + /// public byte[] Random { get; } + /// + /// Gets the time derived from the random bytes. + /// public DateTime Time { get @@ -54,18 +79,39 @@ public DateTime Time } } + /// + /// Gets the session ID. + /// public byte[] SessionId { get; } + /// + /// Gets the ciphers. + /// public int[] Ciphers { get; } + /// + /// Gets or sets the compression data. + /// public byte[]? CompressionData { get; internal set; } + /// + /// Gets the length of the client hello message. + /// internal int ClientHelloLength { get; } + /// + /// Gets or sets the start position of the extensions in the client hello message. + /// internal int ExtensionsStartPosition { get; set; } + /// + /// Gets or sets the extensions in the client hello message. + /// public Dictionary? Extensions { get; set; } + /// + /// Gets the SSL protocol used in the client hello message. + /// public SslProtocols SslProtocol { get diff --git a/src/Titanium.Web.Proxy/Network/Ssl/ServerHelloInfo.cs b/src/Titanium.Web.Proxy/Network/Ssl/ServerHelloInfo.cs index 5c614e5f..f637a862 100644 --- a/src/Titanium.Web.Proxy/Network/Ssl/ServerHelloInfo.cs +++ b/src/Titanium.Web.Proxy/Network/Ssl/ServerHelloInfo.cs @@ -18,6 +18,16 @@ public class ServerHelloInfo "DEFLATE" }; + /// + /// Initializes a new instance of the class. + /// + /// The handshake version. + /// The major version. + /// The minor version. + /// The random bytes. + /// The session ID. + /// The cipher suite. + /// The length of the server hello message. public ServerHelloInfo(int handshakeVersion, int majorVersion, int minorVersion, byte[] random, byte[] sessionId, int cipherSuite, int serverHelloLength) { @@ -29,15 +39,29 @@ public ServerHelloInfo(int handshakeVersion, int majorVersion, int minorVersion, CipherSuite = cipherSuite; ServerHelloLength = serverHelloLength; } - + /// + /// Gets the handshake version. + /// public int HandshakeVersion { get; } + /// + /// Gets the major version. + /// public int MajorVersion { get; } + /// + /// Gets the minor version. + /// public int MinorVersion { get; } + /// + /// Gets the random bytes. + /// public byte[] Random { get; } + /// + /// Gets the time derived from the random bytes. + /// public DateTime Time { get @@ -52,16 +76,34 @@ public DateTime Time } } + /// + /// Gets the session ID. + /// public byte[] SessionId { get; } + /// + /// Gets the cipher suite. + /// public int CipherSuite { get; } + /// + /// Gets or sets the compression method. + /// public byte CompressionMethod { get; set; } + /// + /// Gets the length of the server hello message. + /// internal int ServerHelloLength { get; } - internal int EntensionsStartPosition { get; set; } + /// + /// Gets or sets the start position of the extensions in the server hello message. + /// + internal int ExtensionsStartPosition { get; set; } + /// + /// Gets or sets the extensions in the server hello message. + /// public Dictionary? Extensions { get; set; } private static string SslVersionToString(int major, int minor) diff --git a/src/Titanium.Web.Proxy/Network/Ssl/SslTools.cs b/src/Titanium.Web.Proxy/Network/Ssl/SslTools.cs index 1b419d58..eebef253 100644 --- a/src/Titanium.Web.Proxy/Network/Ssl/SslTools.cs +++ b/src/Titanium.Web.Proxy/Network/Ssl/SslTools.cs @@ -248,7 +248,7 @@ public static async Task IsServerHello(IPeekStream stream, IBufferPool buf peekStream.Position) { CompressionMethod = compressionMethod, - EntensionsStartPosition = extensionsStartPosition, + ExtensionsStartPosition = extensionsStartPosition, Extensions = extensions };