From 75a10f9060eec1e8ea233664d63323f5b6a2781f Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Thu, 30 Aug 2018 12:00:08 -0400 Subject: [PATCH 01/40] move source under src\ directory --- .build/build.ps1 | 2 +- .build/setup.ps1 | 2 +- _config.yml | 2 +- .../App.config | 0 .../Capture.PNG | Bin .../Helpers/ConsoleHelper.cs | 0 .../Program.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ProxyTestController.cs | 0 .../Titanium.Web.Proxy.Examples.Basic.csproj | 2 +- .../App.config | 0 .../Titanium.Web.Proxy.Examples.Wpf/App.xaml | 0 .../App.xaml.cs | 0 .../Capture.PNG | Bin .../MainWindow.xaml | 0 .../MainWindow.xaml.cs | 0 .../Properties/Annotations.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Properties/Resources.Designer.cs | 0 .../Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 0 .../Properties/Settings.settings | 0 .../SessionListItem.cs | 0 .../Titanium.Web.Proxy.Examples.Wpf.csproj | 12 +- .../packages.config | 0 .../Titanium.Web.Proxy.Docs.sln | 0 .../Titanium.Web.Proxy.sln | 30 +- .../Titanium.Web.Proxy.sln.DotSettings | 0 .../Titanium.Web.Proxy}/CertificateHandler.cs | 0 .../Compression/CompressionFactory.cs | 0 .../Compression/DecompressionFactory.cs | 0 .../EventArguments/AsyncEventHandler.cs | 0 .../BeforeSslAuthenticateEventArgs.cs | 0 .../CertificateSelectionEventArgs.cs | 0 .../CertificateValidationEventArgs.cs | 0 .../EventArguments/LimitedStream.cs | 0 .../MultipartRequestPartSentEventArgs.cs | 0 .../EventArguments/SessionEventArgs.cs | 1244 ++++++------ .../EventArguments/SessionEventArgsBase.cs | 0 .../EventArguments/TransformationMode.cs | 0 .../EventArguments/TunnelConnectEventArgs.cs | 0 .../Titanium.Web.Proxy}/ExceptionHandler.cs | 0 .../Exceptions/BodyNotFoundException.cs | 0 .../Exceptions/ProxyAuthorizationException.cs | 74 +- .../Exceptions/ProxyConnectException.cs | 0 .../Exceptions/ProxyException.cs | 58 +- .../Exceptions/ProxyHttpException.cs | 62 +- .../Exceptions/ServerConnectionException.cs | 0 .../ExplicitClientHandler.cs | 0 .../Extensions/FuncExtensions.cs | 0 .../Extensions/SslExtensions.cs | 0 .../Extensions/StreamExtensions.cs | 0 .../Extensions/StringExtensions.cs | 0 .../Extensions/TcpExtensions.cs | 0 .../Titanium.Web.Proxy}/Helpers/HttpHelper.cs | 0 .../Helpers/HttpRequestWriter.cs | 0 .../Helpers/HttpResponseWriter.cs | 0 .../Titanium.Web.Proxy}/Helpers/HttpWriter.cs | 0 .../Helpers/NativeMethods.SystemProxy.cs | 0 .../Helpers/NativeMethods.Tcp.cs | 0 .../Titanium.Web.Proxy}/Helpers/Network.cs | 146 +- .../Titanium.Web.Proxy}/Helpers/ProxyInfo.cs | 0 .../Titanium.Web.Proxy}/Helpers/Ref.cs | 0 .../Titanium.Web.Proxy}/Helpers/RunTime.cs | 0 .../Helpers/SystemProxy.cs | 0 .../Titanium.Web.Proxy}/Helpers/TcpHelper.cs | 0 .../Helpers/WinHttp/NativeMethods.WinHttp.cs | 0 .../Helpers/WinHttp/WinHttpHandle.cs | 0 .../Helpers/WinHttp/WinHttpWebProxyFinder.cs | 0 .../Http/ConnectRequest.cs | 0 .../Http/ConnectResponse.cs | 0 .../Http/HeaderCollection.cs | 0 .../Titanium.Web.Proxy}/Http/HeaderParser.cs | 0 .../Titanium.Web.Proxy}/Http/HttpWebClient.cs | 502 ++--- .../Http/InternalDataStore.cs | 0 .../Titanium.Web.Proxy}/Http/KnownHeaders.cs | 0 .../Titanium.Web.Proxy}/Http/Request.cs | 0 .../Http/RequestResponseBase.cs | 0 .../Titanium.Web.Proxy}/Http/Response.cs | 0 .../Http/Responses/GenericResponse.cs | 0 .../Http/Responses/OkResponse.cs | 0 .../Http/Responses/RedirectResponse.cs | 0 .../Http2/Hpack/Decoder.cs | 0 .../Http2/Hpack/DynamicTable.cs | 0 .../Http2/Hpack/Encoder.cs | 0 .../Http2/Hpack/HpackUtil.cs | 0 .../Http2/Hpack/HuffmanDecoder.cs | 0 .../Http2/Hpack/HuffmanEncoder.cs | 0 .../Http2/Hpack/IHeaderListener.cs | 0 .../Http2/Hpack/StaticTable.cs | 0 .../Titanium.Web.Proxy}/Http2/Http2Helper.cs | 0 .../Models/ExplicitProxyEndPoint.cs | 0 .../Models/ExternalProxy.cs | 182 +- .../Titanium.Web.Proxy}/Models/HttpHeader.cs | 0 .../Models/ProxyAuthenticationContext.cs | 0 .../Models/ProxyEndPoint.cs | 0 .../Models/ProxyProtocolType.cs | 0 .../Models/TransparentProxyEndPoint.cs | 0 .../Network/CachedCertificate.cs | 0 .../Network/Certificate/BCCertificateMaker.cs | 0 .../Network/Certificate/ICertificateMaker.cs | 0 .../Certificate/WinCertificateMaker.cs | 0 .../Network/CertificateManager.cs | 0 .../Network/DebugCustomBufferedStream.cs | 0 .../Network/ProxyClient.cs | 0 .../Network/RetryPolicy.cs | 0 .../Network/Tcp/TcpClientConnection.cs | 0 .../Network/Tcp/TcpConnectionFactory.cs | 1092 +++++------ .../Network/Tcp/TcpServerConnection.cs | 0 .../Network/WinAuth/Security/Common.cs | 0 .../Network/WinAuth/Security/LittleEndian.cs | 0 .../Network/WinAuth/Security/Message.cs | 0 .../Network/WinAuth/Security/State.cs | 0 .../WinAuth/Security/WinAuthEndPoint.cs | 0 .../Network/WinAuth/WinAuthHandler.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ProxyAuthorizationHandler.cs | 318 ++-- .../Titanium.Web.Proxy}/ProxyServer.cs | 1694 ++++++++--------- .../Titanium.Web.Proxy}/RequestHandler.cs | 840 ++++---- .../Titanium.Web.Proxy}/ResponseHandler.cs | 310 +-- .../Titanium.Web.Proxy}/Settings.StyleCop | 0 .../Shared/ProxyConstants.cs | 0 .../Titanium.Web.Proxy}/StrongNameKey.snk | Bin .../Titanium.Web.Proxy.Docs.csproj | 0 .../Titanium.Web.Proxy.csproj | 126 +- .../Titanium.Web.Proxy.nuspec | 0 .../TransparentClientHandler.cs | 0 .../Titanium.Web.Proxy}/WebSocketHandler.cs | 0 .../Titanium.Web.Proxy}/WinAuthHandler.cs | 0 .../Titanium.Web.Proxy}/app.config | 0 .../Titanium.Web.Proxy}/packages.config | 0 .../Properties/AssemblyInfo.cs | 0 .../SslTests.cs | 0 ...Titanium.Web.Proxy.IntegrationTests.csproj | 4 +- .../CertificateManagerTests.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ProxyServerTests.cs | 0 .../StrongNameKey.snk | Bin .../SystemProxyTest.cs | 0 .../Titanium.Web.Proxy.UnitTests.csproj | 10 +- .../WinAuthTests.cs | 0 141 files changed, 3356 insertions(+), 3356 deletions(-) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/App.config (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/Capture.PNG (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/Helpers/ConsoleHelper.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/Program.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/Properties/AssemblyInfo.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj (80%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/App.config (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/App.xaml (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/App.xaml.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/Annotations.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/AssemblyInfo.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.Designer.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.resx (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.Designer.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.settings (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs (100%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj (97%) rename {Examples => examples}/Titanium.Web.Proxy.Examples.Wpf/packages.config (100%) rename Titanium.Web.Proxy.Docs.sln => src/Titanium.Web.Proxy.Docs.sln (100%) rename Titanium.Web.Proxy.sln => src/Titanium.Web.Proxy.sln (72%) rename Titanium.Web.Proxy.sln.DotSettings => src/Titanium.Web.Proxy.sln.DotSettings (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/CertificateHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Compression/CompressionFactory.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Compression/DecompressionFactory.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/AsyncEventHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/BeforeSslAuthenticateEventArgs.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/CertificateSelectionEventArgs.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/CertificateValidationEventArgs.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/LimitedStream.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/MultipartRequestPartSentEventArgs.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/SessionEventArgs.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/SessionEventArgsBase.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/TransformationMode.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/EventArguments/TunnelConnectEventArgs.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/ExceptionHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/BodyNotFoundException.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/ProxyAuthorizationException.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/ProxyConnectException.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/ProxyException.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/ProxyHttpException.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Exceptions/ServerConnectionException.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/ExplicitClientHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Extensions/FuncExtensions.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Extensions/SslExtensions.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Extensions/StreamExtensions.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Extensions/StringExtensions.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Extensions/TcpExtensions.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/HttpHelper.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/HttpRequestWriter.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/HttpResponseWriter.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/HttpWriter.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/NativeMethods.SystemProxy.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/NativeMethods.Tcp.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/Network.cs (96%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/ProxyInfo.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/Ref.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/RunTime.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/SystemProxy.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/TcpHelper.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/WinHttp/NativeMethods.WinHttp.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/WinHttp/WinHttpHandle.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Helpers/WinHttp/WinHttpWebProxyFinder.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/ConnectRequest.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/ConnectResponse.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/HeaderCollection.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/HeaderParser.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/HttpWebClient.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/InternalDataStore.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/KnownHeaders.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/Request.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/RequestResponseBase.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/Response.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/Responses/GenericResponse.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/Responses/OkResponse.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http/Responses/RedirectResponse.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/Decoder.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/DynamicTable.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/Encoder.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/HpackUtil.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/HuffmanDecoder.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/HuffmanEncoder.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/IHeaderListener.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Hpack/StaticTable.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Http2/Http2Helper.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/ExplicitProxyEndPoint.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/ExternalProxy.cs (96%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/HttpHeader.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/ProxyAuthenticationContext.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/ProxyEndPoint.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/ProxyProtocolType.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Models/TransparentProxyEndPoint.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/CachedCertificate.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Certificate/BCCertificateMaker.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Certificate/ICertificateMaker.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Certificate/WinCertificateMaker.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/CertificateManager.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/DebugCustomBufferedStream.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/ProxyClient.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/RetryPolicy.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Tcp/TcpClientConnection.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Tcp/TcpConnectionFactory.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/Tcp/TcpServerConnection.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/Security/Common.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/Security/LittleEndian.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/Security/Message.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/Security/State.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/Security/WinAuthEndPoint.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Network/WinAuth/WinAuthHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Properties/AssemblyInfo.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/ProxyAuthorizationHandler.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/ProxyServer.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/RequestHandler.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/ResponseHandler.cs (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Settings.StyleCop (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Shared/ProxyConstants.cs (100%) rename {Tests/Titanium.Web.Proxy.UnitTests => src/Titanium.Web.Proxy}/StrongNameKey.snk (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Titanium.Web.Proxy.Docs.csproj (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Titanium.Web.Proxy.csproj (97%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/Titanium.Web.Proxy.nuspec (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/TransparentClientHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/WebSocketHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/WinAuthHandler.cs (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/app.config (100%) rename {Titanium.Web.Proxy => src/Titanium.Web.Proxy}/packages.config (100%) rename {Tests => tests}/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs (100%) rename {Tests => tests}/Titanium.Web.Proxy.IntegrationTests/SslTests.cs (100%) rename {Tests => tests}/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj (96%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs (100%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs (100%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/ProxyServerTests.cs (100%) rename {Titanium.Web.Proxy => tests/Titanium.Web.Proxy.UnitTests}/StrongNameKey.snk (100%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs (100%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj (96%) rename {Tests => tests}/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs (100%) diff --git a/.build/build.ps1 b/.build/build.ps1 index 160793dcc..1e79ce7f0 100644 --- a/.build/build.ps1 +++ b/.build/build.ps1 @@ -2,7 +2,7 @@ $PSake.use_exit_on_error = $true $Here = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" -$SolutionRoot = (Split-Path -parent $Here) +$SolutionRoot = "$(Split-Path -parent $Here)\src" $ProjectName = "Titanium.Web.Proxy" $GitHubProjectName = "Titanium-Web-Proxy" diff --git a/.build/setup.ps1 b/.build/setup.ps1 index e07a784db..a0ccb55a1 100644 --- a/.build/setup.ps1 +++ b/.build/setup.ps1 @@ -6,7 +6,7 @@ param ( function Install-Chocolatey() { - if(-not $env:ChocolateyInstall -or -not (Test-Path "$env:ChocolateyInstall")) + if(-not $env:ChocolateyInstall -or -not (Test-Path "$env:ChocolateyInstall\*")) { Write-Output "Chocolatey Not Found, Installing..." iex ((new-object net.webclient).DownloadString('http://chocolatey.org/install.ps1')) diff --git a/_config.yml b/_config.yml index e8034a2e9..7ceb9188b 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1 @@ -baseurl: /Titanium-Web-Proxy +baseurl: /src diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/App.config b/examples/Titanium.Web.Proxy.Examples.Basic/App.config similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/App.config rename to examples/Titanium.Web.Proxy.Examples.Basic/App.config diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG b/examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG rename to examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/Helpers/ConsoleHelper.cs b/examples/Titanium.Web.Proxy.Examples.Basic/Helpers/ConsoleHelper.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/Helpers/ConsoleHelper.cs rename to examples/Titanium.Web.Proxy.Examples.Basic/Helpers/ConsoleHelper.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs b/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/Program.cs rename to examples/Titanium.Web.Proxy.Examples.Basic/Program.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/Properties/AssemblyInfo.cs b/examples/Titanium.Web.Proxy.Examples.Basic/Properties/AssemblyInfo.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/Properties/AssemblyInfo.cs rename to examples/Titanium.Web.Proxy.Examples.Basic/Properties/AssemblyInfo.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs rename to examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs 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 similarity index 80% rename from Examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj rename to examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj index 2766cec5d..9141a98c4 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 @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/App.config b/examples/Titanium.Web.Proxy.Examples.Wpf/App.config similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/App.config rename to examples/Titanium.Web.Proxy.Examples.Wpf/App.config diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml b/examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml rename to examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/App.xaml.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG b/examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG rename to examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml rename to examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Annotations.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Annotations.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Annotations.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Annotations.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/AssemblyInfo.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/AssemblyInfo.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/AssemblyInfo.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/AssemblyInfo.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.Designer.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.Designer.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.Designer.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.Designer.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.resx b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.resx similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.resx rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Resources.resx diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.Designer.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.Designer.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.Designer.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.Designer.cs diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.settings b/examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.settings similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.settings rename to examples/Titanium.Web.Proxy.Examples.Wpf/Properties/Settings.settings diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs rename to examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs 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 similarity index 97% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj rename to examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj index be9c1b957..f93a1569b 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 @@ -116,12 +116,6 @@ - - - {8d73a1be-868c-42d2-9ece-f32cc1a02906} - Titanium.Web.Proxy - - False @@ -129,5 +123,11 @@ false + + + {91018b6d-a7a9-45be-9cb3-79cbb8b169a6} + Titanium.Web.Proxy + + \ No newline at end of file diff --git a/Examples/Titanium.Web.Proxy.Examples.Wpf/packages.config b/examples/Titanium.Web.Proxy.Examples.Wpf/packages.config similarity index 100% rename from Examples/Titanium.Web.Proxy.Examples.Wpf/packages.config rename to examples/Titanium.Web.Proxy.Examples.Wpf/packages.config diff --git a/Titanium.Web.Proxy.Docs.sln b/src/Titanium.Web.Proxy.Docs.sln similarity index 100% rename from Titanium.Web.Proxy.Docs.sln rename to src/Titanium.Web.Proxy.Docs.sln diff --git a/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln similarity index 72% rename from Titanium.Web.Proxy.sln rename to src/Titanium.Web.Proxy.sln index e4969f3fd..e431cf2a3 100644 --- a/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 15.0.26906.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{B6DBABDC-C985-4872-9C38-B4E5079CBC4B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B84B-9283-4E9C-8C43-A234E9AA3EAA}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -29,13 +27,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AC9AE37A EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC1E0789-D348-49CF-8B67-5E99D50EDF64}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.UnitTests", "Tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.UnitTests", "..\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.IntegrationTests", "Tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{32231301-B0FB-4F9E-98DF-B3E8A88F4C16}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.IntegrationTests", "..\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{32231301-B0FB-4F9E-98DF-B3E8A88F4C16}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples.Wpf", "Examples\Titanium.Web.Proxy.Examples.Wpf\Titanium.Web.Proxy.Examples.Wpf.csproj", "{4406CE17-9A39-4F28-8363-6169A4F799C1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.Examples.Basic", "..\examples\Titanium.Web.Proxy.Examples.Basic\Titanium.Web.Proxy.Examples.Basic.csproj", "{1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples.Basic", "Examples\Titanium.Web.Proxy.Examples.Basic\Titanium.Web.Proxy.Examples.Basic.csproj", "{9A2C6980-90D1-4082-AD60-B2428F3D6197}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples.Wpf", "..\examples\Titanium.Web.Proxy.Examples.Wpf\Titanium.Web.Proxy.Examples.Wpf.csproj", "{4406CE17-9A39-4F28-8363-6169A4F799C1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -43,10 +43,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|Any CPU.Build.0 = Release|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|Any CPU.Build.0 = Release|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -55,14 +55,14 @@ Global {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|Any CPU.Build.0 = Debug|Any CPU {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.ActiveCfg = Release|Any CPU {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.Build.0 = Release|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|Any CPU.Build.0 = Release|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|Any CPU.Build.0 = Release|Any CPU - {9A2C6980-90D1-4082-AD60-B2428F3D6197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A2C6980-90D1-4082-AD60-B2428F3D6197}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A2C6980-90D1-4082-AD60-B2428F3D6197}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A2C6980-90D1-4082-AD60-B2428F3D6197}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -70,8 +70,8 @@ Global GlobalSection(NestedProjects) = preSolution {B517E3D0-D03B-436F-AB03-34BA0D5321AF} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} {32231301-B0FB-4F9E-98DF-B3E8A88F4C16} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} {4406CE17-9A39-4F28-8363-6169A4F799C1} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} - {9A2C6980-90D1-4082-AD60-B2428F3D6197} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 diff --git a/Titanium.Web.Proxy.sln.DotSettings b/src/Titanium.Web.Proxy.sln.DotSettings similarity index 100% rename from Titanium.Web.Proxy.sln.DotSettings rename to src/Titanium.Web.Proxy.sln.DotSettings diff --git a/Titanium.Web.Proxy/CertificateHandler.cs b/src/Titanium.Web.Proxy/CertificateHandler.cs similarity index 100% rename from Titanium.Web.Proxy/CertificateHandler.cs rename to src/Titanium.Web.Proxy/CertificateHandler.cs diff --git a/Titanium.Web.Proxy/Compression/CompressionFactory.cs b/src/Titanium.Web.Proxy/Compression/CompressionFactory.cs similarity index 100% rename from Titanium.Web.Proxy/Compression/CompressionFactory.cs rename to src/Titanium.Web.Proxy/Compression/CompressionFactory.cs diff --git a/Titanium.Web.Proxy/Compression/DecompressionFactory.cs b/src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs similarity index 100% rename from Titanium.Web.Proxy/Compression/DecompressionFactory.cs rename to src/Titanium.Web.Proxy/Compression/DecompressionFactory.cs diff --git a/Titanium.Web.Proxy/EventArguments/AsyncEventHandler.cs b/src/Titanium.Web.Proxy/EventArguments/AsyncEventHandler.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/AsyncEventHandler.cs rename to src/Titanium.Web.Proxy/EventArguments/AsyncEventHandler.cs diff --git a/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs diff --git a/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs diff --git a/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs diff --git a/Titanium.Web.Proxy/EventArguments/LimitedStream.cs b/src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/LimitedStream.cs rename to src/Titanium.Web.Proxy/EventArguments/LimitedStream.cs diff --git a/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs diff --git a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs similarity index 97% rename from Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index f9fd2f24d..03f98065c 100644 --- a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -1,622 +1,622 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using StreamExtended.Network; -using Titanium.Web.Proxy.Compression; -using Titanium.Web.Proxy.Helpers; -using Titanium.Web.Proxy.Http; -using Titanium.Web.Proxy.Http.Responses; -using Titanium.Web.Proxy.Models; - -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. - /// - public class SessionEventArgs : SessionEventArgsBase - { - private static readonly byte[] emptyData = new byte[0]; - - /// - /// Backing field for corresponding public property - /// - private bool reRequest; - - /// - /// Constructor to initialize the proxy - /// - internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, - CancellationTokenSource cancellationTokenSource) - : this(server, endPoint, null, cancellationTokenSource) - { - } - - protected SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, - Request request, CancellationTokenSource cancellationTokenSource) - : base(server, endPoint, cancellationTokenSource, request) - { - } - - private bool hasMulipartEventSubscribers => MultipartRequestPartSent != null; - - /// - /// Should we send the request again ? - /// - public bool ReRequest - { - get => reRequest; - set - { - if (WebSession.Response.StatusCode == 0) - { - throw new Exception("Response status code is empty. Cannot request again a request " + "which was never send to server."); - } - - reRequest = value; - } - } - - /// - /// Occurs when multipart request part sent. - /// - public event EventHandler MultipartRequestPartSent; - - private ICustomStreamReader getStreamReader(bool isRequest) - { - return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream; - } - - private HttpWriter getStreamWriter(bool isRequest) - { - return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter; - } - - /// - /// Read request body content as bytes[] for current session - /// - private async Task readRequestBodyAsync(CancellationToken cancellationToken) - { - WebSession.Request.EnsureBodyAvailable(false); - - var request = WebSession.Request; - - // If not already read (not cached yet) - if (!request.IsBodyRead) - { - var body = await readBodyAsync(true, cancellationToken); - request.Body = body; - - // Now set the flag to true - // So that next time we can deliver body from cache - request.IsBodyRead = true; - OnDataSent(body, 0, body.Length); - } - } - - /// - /// reinit response object - /// - internal async Task ClearResponse(CancellationToken cancellationToken) - { - // syphon out the response body from server - await SyphonOutBodyAsync(false, cancellationToken); - WebSession.Response = new Response(); - } - - internal void OnMultipartRequestPartSent(string boundary, HeaderCollection headers) - { - try - { - MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(boundary, headers)); - } - catch (Exception ex) - { - exceptionFunc(new Exception("Exception thrown in user event", ex)); - } - } - - /// - /// Read response body as byte[] for current response - /// - private async Task readResponseBodyAsync(CancellationToken cancellationToken) - { - if (!WebSession.Request.Locked) - { - throw new Exception("You cannot read the response body before request is made to server."); - } - - var response = WebSession.Response; - if (!response.HasBody) - { - return; - } - - // If not already read (not cached yet) - if (!response.IsBodyRead) - { - var body = await readBodyAsync(false, cancellationToken); - response.Body = body; - - // Now set the flag to true - // So that next time we can deliver body from cache - response.IsBodyRead = true; - OnDataReceived(body, 0, body.Length); - } - } - - private async Task readBodyAsync(bool isRequest, CancellationToken cancellationToken) - { - using (var bodyStream = new MemoryStream()) - { - var writer = new HttpWriter(bodyStream, bufferPool, bufferSize); - - if (isRequest) - { - await CopyRequestBodyAsync(writer, TransformationMode.Uncompress, cancellationToken); - } - else - { - await CopyResponseBodyAsync(writer, TransformationMode.Uncompress, cancellationToken); - } - - return bodyStream.ToArray(); - } - } - - /// - /// Syphon out any left over data in given request/response from backing tcp connection. - /// When user modifies the response/request we need to do this to reuse tcp connections. - /// - /// - /// - /// - internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken) - { - var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; - if (requestResponse.OriginalIsBodyRead || !requestResponse.OriginalHasBody) - { - return; - } - - using (var bodyStream = new MemoryStream()) - { - var writer = new HttpWriter(bodyStream, bufferPool, bufferSize); - await copyBodyAsync(isRequest, true, writer, TransformationMode.None, null, cancellationToken); - } - } - - /// - /// This is called when the request is PUT/POST/PATCH to read the body - /// - /// - internal async Task CopyRequestBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken) - { - var request = WebSession.Request; - - long contentLength = request.ContentLength; - - // send the request body bytes to server - if (contentLength > 0 && hasMulipartEventSubscribers && request.IsMultipartFormData) - { - var reader = getStreamReader(true); - string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType); - - using (var copyStream = new CopyStream(reader, writer, bufferPool, bufferSize)) - { - while (contentLength > copyStream.ReadBytes) - { - long read = await readUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken); - if (read == 0) - { - break; - } - - if (contentLength > copyStream.ReadBytes) - { - var headers = new HeaderCollection(); - await HeaderParser.ReadHeaders(copyStream, headers, cancellationToken); - OnMultipartRequestPartSent(boundary, headers); - } - } - - await copyStream.FlushAsync(cancellationToken); - } - } - else - { - await copyBodyAsync(true, false, writer, transformation, OnDataSent, cancellationToken); - } - } - - internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken) - { - await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken); - } - - private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action onCopy, CancellationToken cancellationToken) - { - var stream = getStreamReader(isRequest); - - var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; - - bool isChunked = useOriginalHeaderValues? requestResponse.OriginalIsChunked : requestResponse.IsChunked; - long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength; - - if (transformation == TransformationMode.None) - { - await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken); - return; - } - - LimitedStream limitedStream; - Stream decompressStream = null; - - string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding; - - Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength); - - if (transformation == TransformationMode.Uncompress && contentEncoding != null) - { - s = decompressStream = DecompressionFactory.Create(contentEncoding, s); - } - - try - { - using (var bufStream = new CustomBufferedStream(s, bufferPool, bufferSize, true)) - { - await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken); - } - } - finally - { - decompressStream?.Dispose(); - - await limitedStream.Finish(); - limitedStream.Dispose(); - } - } - - /// - /// Read a line from the byte stream - /// - /// - private async Task readUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken) - { - int bufferDataLength = 0; - - var buffer = bufferPool.GetBuffer(bufferSize); - try - { - int boundaryLength = boundary.Length + 4; - long bytesRead = 0; - - while (bytesRead < totalBytesToRead && (reader.DataAvailable || await reader.FillBufferAsync(cancellationToken))) - { - byte newChar = reader.ReadByteFromBuffer(); - buffer[bufferDataLength] = newChar; - - bufferDataLength++; - bytesRead++; - - if (bufferDataLength >= boundaryLength) - { - int startIdx = bufferDataLength - boundaryLength; - if (buffer[startIdx] == '-' && buffer[startIdx + 1] == '-') - { - startIdx += 2; - bool ok = true; - for (int i = 0; i < boundary.Length; i++) - { - if (buffer[startIdx + i] != boundary[i]) - { - ok = false; - break; - } - } - - if (ok) - { - break; - } - } - } - - if (bufferDataLength == buffer.Length) - { - // boundary is not longer than 70 bytes according to the specification, so keeping the last 100 (minimum 74) bytes is enough - const int bytesToKeep = 100; - Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep); - bufferDataLength = bytesToKeep; - } - } - - return bytesRead; - } - finally - { - bufferPool.ReturnBuffer(buffer); - } - } - - /// - /// Gets the request body as bytes. - /// - /// Optional cancellation token for this async task. - /// The body as bytes. - public async Task GetRequestBody(CancellationToken cancellationToken = default) - { - if (!WebSession.Request.IsBodyRead) - { - await readRequestBodyAsync(cancellationToken); - } - - return WebSession.Request.Body; - } - - /// - /// Gets the request body as string. - /// - /// Optional cancellation token for this async task. - /// The body as string. - public async Task GetRequestBodyAsString(CancellationToken cancellationToken = default) - { - if (!WebSession.Request.IsBodyRead) - { - await readRequestBodyAsync(cancellationToken); - } - - return WebSession.Request.BodyString; - } - - /// - /// Sets the request body. - /// - /// The request body bytes. - public void SetRequestBody(byte[] body) - { - var request = WebSession.Request; - if (request.Locked) - { - throw new Exception("You cannot call this function after request is made to server."); - } - - request.Body = body; - } - - /// - /// Sets the body with the specified string. - /// - /// The request body string to set. - public void SetRequestBodyString(string body) - { - if (WebSession.Request.Locked) - { - throw new Exception("You cannot call this function after request is made to server."); - } - - SetRequestBody(WebSession.Request.Encoding.GetBytes(body)); - } - - - /// - /// Gets the response body as bytes. - /// - /// Optional cancellation token for this async task. - /// The resulting bytes. - public async Task GetResponseBody(CancellationToken cancellationToken = default) - { - if (!WebSession.Response.IsBodyRead) - { - await readResponseBodyAsync(cancellationToken); - } - - return WebSession.Response.Body; - } - - /// - /// Gets the response body as string. - /// - /// Optional cancellation token for this async task. - /// The string body. - public async Task GetResponseBodyAsString(CancellationToken cancellationToken = default) - { - if (!WebSession.Response.IsBodyRead) - { - await readResponseBodyAsync(cancellationToken); - } - - return WebSession.Response.BodyString; - } - - /// - /// Set the response body bytes. - /// - /// The body bytes to set. - public void SetResponseBody(byte[] body) - { - if (!WebSession.Request.Locked) - { - throw new Exception("You cannot call this function before request is made to server."); - } - - var response = WebSession.Response; - response.Body = body; - } - - /// - /// Replace the response body with the specified string. - /// - /// The body string to set. - public void SetResponseBodyString(string body) - { - if (!WebSession.Request.Locked) - { - throw new Exception("You cannot call this function before request is made to server."); - } - - var bodyBytes = WebSession.Response.Encoding.GetBytes(body); - - SetResponseBody(bodyBytes); - } - - /// - /// Before request is made to server respond with the specified HTML string to client - /// and ignore the request. - /// - /// HTML content to sent. - /// HTTP response headers. - /// Close the server connection used by request if any? - public void Ok(string html, Dictionary headers = null, - bool closeServerConnection = false) - { - var response = new OkResponse(); - if (headers != null) - { - response.Headers.AddHeaders(headers); - } - - response.HttpVersion = WebSession.Request.HttpVersion; - response.Body = response.Encoding.GetBytes(html ?? string.Empty); - - Respond(response, closeServerConnection); - } - - /// - /// Before request is made to server respond with the specified byte[] to client - /// and ignore the request. - /// - /// The html content bytes. - /// The HTTP headers. - /// Close the server connection used by request if any? - public void Ok(byte[] result, Dictionary headers = null, - bool closeServerConnection = false) - { - var response = new OkResponse(); - response.Headers.AddHeaders(headers); - response.HttpVersion = WebSession.Request.HttpVersion; - response.Body = result; - - Respond(response, closeServerConnection); - } - - /// - /// Before request is made to server  - /// respond with the specified HTML string and the specified status to client. - /// And then ignore the request.  - /// - /// The html content. - /// The HTTP status code. - /// The HTTP headers. - /// Close the server connection used by request if any? - public void GenericResponse(string html, HttpStatusCode status, - Dictionary headers = null, bool closeServerConnection = false) - { - var response = new GenericResponse(status); - response.HttpVersion = WebSession.Request.HttpVersion; - response.Headers.AddHeaders(headers); - response.Body = response.Encoding.GetBytes(html ?? string.Empty); - - Respond(response, closeServerConnection); - } - - /// - /// Before request is made to server respond with the specified byte[], - /// the specified status to client. And then ignore the request. - /// - /// The bytes to sent. - /// The HTTP status code. - /// The HTTP headers. - /// Close the server connection used by request if any? - public void GenericResponse(byte[] result, HttpStatusCode status, - Dictionary headers, bool closeServerConnection = false) - { - var response = new GenericResponse(status); - response.HttpVersion = WebSession.Request.HttpVersion; - response.Headers.AddHeaders(headers); - response.Body = result; - - Respond(response, closeServerConnection); - } - - /// - /// Redirect to provided URL. - /// - /// The URL to redirect. - /// Close the server connection used by request if any? - public void Redirect(string url, bool closeServerConnection = false) - { - var response = new RedirectResponse(); - response.HttpVersion = WebSession.Request.HttpVersion; - response.Headers.AddHeader(KnownHeaders.Location, url); - response.Body = emptyData; - - Respond(response, closeServerConnection); - } - - /// - /// Respond with given response object to client. - /// - /// The response object. - /// Close the server connection used by request if any? - public void Respond(Response response, bool closeServerConnection = false) - { - //request already send/ready to be sent. - if (WebSession.Request.Locked) - { - //response already received from server and ready to be sent to client. - if (WebSession.Response.Locked) - { - throw new Exception("You cannot call this function after response is sent to the client."); - } - - //cleanup original response. - if (closeServerConnection) - { - //no need to cleanup original connection. - //it will be closed any way. - TerminateServerConnection(); - } - - response.SetOriginalHeaders(WebSession.Response); - - //response already received from server but not yet ready to sent to client. - WebSession.Response = response; - WebSession.Response.Locked = true; - } - //request not yet sent/not yet ready to be sent. - else - { - WebSession.Request.Locked = true; - WebSession.Request.CancelRequest = true; - - //set new response. - WebSession.Response = response; - WebSession.Response.Locked = true; - } - - } - - /// - /// Terminate the connection to server at the end of this HTTP request/response session. - /// - public void TerminateServerConnection() - { - WebSession.CloseServerConnection = true; - } - - /// - /// Implement any cleanup here - /// - public override void Dispose() - { - MultipartRequestPartSent = null; - base.Dispose(); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using StreamExtended.Network; +using Titanium.Web.Proxy.Compression; +using Titanium.Web.Proxy.Helpers; +using Titanium.Web.Proxy.Http; +using Titanium.Web.Proxy.Http.Responses; +using Titanium.Web.Proxy.Models; + +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. + /// + public class SessionEventArgs : SessionEventArgsBase + { + private static readonly byte[] emptyData = new byte[0]; + + /// + /// Backing field for corresponding public property + /// + private bool reRequest; + + /// + /// Constructor to initialize the proxy + /// + internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, + CancellationTokenSource cancellationTokenSource) + : this(server, endPoint, null, cancellationTokenSource) + { + } + + protected SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, + Request request, CancellationTokenSource cancellationTokenSource) + : base(server, endPoint, cancellationTokenSource, request) + { + } + + private bool hasMulipartEventSubscribers => MultipartRequestPartSent != null; + + /// + /// Should we send the request again ? + /// + public bool ReRequest + { + get => reRequest; + set + { + if (WebSession.Response.StatusCode == 0) + { + throw new Exception("Response status code is empty. Cannot request again a request " + "which was never send to server."); + } + + reRequest = value; + } + } + + /// + /// Occurs when multipart request part sent. + /// + public event EventHandler MultipartRequestPartSent; + + private ICustomStreamReader getStreamReader(bool isRequest) + { + return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream; + } + + private HttpWriter getStreamWriter(bool isRequest) + { + return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter; + } + + /// + /// Read request body content as bytes[] for current session + /// + private async Task readRequestBodyAsync(CancellationToken cancellationToken) + { + WebSession.Request.EnsureBodyAvailable(false); + + var request = WebSession.Request; + + // If not already read (not cached yet) + if (!request.IsBodyRead) + { + var body = await readBodyAsync(true, cancellationToken); + request.Body = body; + + // Now set the flag to true + // So that next time we can deliver body from cache + request.IsBodyRead = true; + OnDataSent(body, 0, body.Length); + } + } + + /// + /// reinit response object + /// + internal async Task ClearResponse(CancellationToken cancellationToken) + { + // syphon out the response body from server + await SyphonOutBodyAsync(false, cancellationToken); + WebSession.Response = new Response(); + } + + internal void OnMultipartRequestPartSent(string boundary, HeaderCollection headers) + { + try + { + MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(boundary, headers)); + } + catch (Exception ex) + { + exceptionFunc(new Exception("Exception thrown in user event", ex)); + } + } + + /// + /// Read response body as byte[] for current response + /// + private async Task readResponseBodyAsync(CancellationToken cancellationToken) + { + if (!WebSession.Request.Locked) + { + throw new Exception("You cannot read the response body before request is made to server."); + } + + var response = WebSession.Response; + if (!response.HasBody) + { + return; + } + + // If not already read (not cached yet) + if (!response.IsBodyRead) + { + var body = await readBodyAsync(false, cancellationToken); + response.Body = body; + + // Now set the flag to true + // So that next time we can deliver body from cache + response.IsBodyRead = true; + OnDataReceived(body, 0, body.Length); + } + } + + private async Task readBodyAsync(bool isRequest, CancellationToken cancellationToken) + { + using (var bodyStream = new MemoryStream()) + { + var writer = new HttpWriter(bodyStream, bufferPool, bufferSize); + + if (isRequest) + { + await CopyRequestBodyAsync(writer, TransformationMode.Uncompress, cancellationToken); + } + else + { + await CopyResponseBodyAsync(writer, TransformationMode.Uncompress, cancellationToken); + } + + return bodyStream.ToArray(); + } + } + + /// + /// Syphon out any left over data in given request/response from backing tcp connection. + /// When user modifies the response/request we need to do this to reuse tcp connections. + /// + /// + /// + /// + internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken) + { + var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; + if (requestResponse.OriginalIsBodyRead || !requestResponse.OriginalHasBody) + { + return; + } + + using (var bodyStream = new MemoryStream()) + { + var writer = new HttpWriter(bodyStream, bufferPool, bufferSize); + await copyBodyAsync(isRequest, true, writer, TransformationMode.None, null, cancellationToken); + } + } + + /// + /// This is called when the request is PUT/POST/PATCH to read the body + /// + /// + internal async Task CopyRequestBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken) + { + var request = WebSession.Request; + + long contentLength = request.ContentLength; + + // send the request body bytes to server + if (contentLength > 0 && hasMulipartEventSubscribers && request.IsMultipartFormData) + { + var reader = getStreamReader(true); + string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType); + + using (var copyStream = new CopyStream(reader, writer, bufferPool, bufferSize)) + { + while (contentLength > copyStream.ReadBytes) + { + long read = await readUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken); + if (read == 0) + { + break; + } + + if (contentLength > copyStream.ReadBytes) + { + var headers = new HeaderCollection(); + await HeaderParser.ReadHeaders(copyStream, headers, cancellationToken); + OnMultipartRequestPartSent(boundary, headers); + } + } + + await copyStream.FlushAsync(cancellationToken); + } + } + else + { + await copyBodyAsync(true, false, writer, transformation, OnDataSent, cancellationToken); + } + } + + internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken) + { + await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken); + } + + private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action onCopy, CancellationToken cancellationToken) + { + var stream = getStreamReader(isRequest); + + var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; + + bool isChunked = useOriginalHeaderValues? requestResponse.OriginalIsChunked : requestResponse.IsChunked; + long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength; + + if (transformation == TransformationMode.None) + { + await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken); + return; + } + + LimitedStream limitedStream; + Stream decompressStream = null; + + string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding; + + Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength); + + if (transformation == TransformationMode.Uncompress && contentEncoding != null) + { + s = decompressStream = DecompressionFactory.Create(contentEncoding, s); + } + + try + { + using (var bufStream = new CustomBufferedStream(s, bufferPool, bufferSize, true)) + { + await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken); + } + } + finally + { + decompressStream?.Dispose(); + + await limitedStream.Finish(); + limitedStream.Dispose(); + } + } + + /// + /// Read a line from the byte stream + /// + /// + private async Task readUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken) + { + int bufferDataLength = 0; + + var buffer = bufferPool.GetBuffer(bufferSize); + try + { + int boundaryLength = boundary.Length + 4; + long bytesRead = 0; + + while (bytesRead < totalBytesToRead && (reader.DataAvailable || await reader.FillBufferAsync(cancellationToken))) + { + byte newChar = reader.ReadByteFromBuffer(); + buffer[bufferDataLength] = newChar; + + bufferDataLength++; + bytesRead++; + + if (bufferDataLength >= boundaryLength) + { + int startIdx = bufferDataLength - boundaryLength; + if (buffer[startIdx] == '-' && buffer[startIdx + 1] == '-') + { + startIdx += 2; + bool ok = true; + for (int i = 0; i < boundary.Length; i++) + { + if (buffer[startIdx + i] != boundary[i]) + { + ok = false; + break; + } + } + + if (ok) + { + break; + } + } + } + + if (bufferDataLength == buffer.Length) + { + // boundary is not longer than 70 bytes according to the specification, so keeping the last 100 (minimum 74) bytes is enough + const int bytesToKeep = 100; + Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep); + bufferDataLength = bytesToKeep; + } + } + + return bytesRead; + } + finally + { + bufferPool.ReturnBuffer(buffer); + } + } + + /// + /// Gets the request body as bytes. + /// + /// Optional cancellation token for this async task. + /// The body as bytes. + public async Task GetRequestBody(CancellationToken cancellationToken = default) + { + if (!WebSession.Request.IsBodyRead) + { + await readRequestBodyAsync(cancellationToken); + } + + return WebSession.Request.Body; + } + + /// + /// Gets the request body as string. + /// + /// Optional cancellation token for this async task. + /// The body as string. + public async Task GetRequestBodyAsString(CancellationToken cancellationToken = default) + { + if (!WebSession.Request.IsBodyRead) + { + await readRequestBodyAsync(cancellationToken); + } + + return WebSession.Request.BodyString; + } + + /// + /// Sets the request body. + /// + /// The request body bytes. + public void SetRequestBody(byte[] body) + { + var request = WebSession.Request; + if (request.Locked) + { + throw new Exception("You cannot call this function after request is made to server."); + } + + request.Body = body; + } + + /// + /// Sets the body with the specified string. + /// + /// The request body string to set. + public void SetRequestBodyString(string body) + { + if (WebSession.Request.Locked) + { + throw new Exception("You cannot call this function after request is made to server."); + } + + SetRequestBody(WebSession.Request.Encoding.GetBytes(body)); + } + + + /// + /// Gets the response body as bytes. + /// + /// Optional cancellation token for this async task. + /// The resulting bytes. + public async Task GetResponseBody(CancellationToken cancellationToken = default) + { + if (!WebSession.Response.IsBodyRead) + { + await readResponseBodyAsync(cancellationToken); + } + + return WebSession.Response.Body; + } + + /// + /// Gets the response body as string. + /// + /// Optional cancellation token for this async task. + /// The string body. + public async Task GetResponseBodyAsString(CancellationToken cancellationToken = default) + { + if (!WebSession.Response.IsBodyRead) + { + await readResponseBodyAsync(cancellationToken); + } + + return WebSession.Response.BodyString; + } + + /// + /// Set the response body bytes. + /// + /// The body bytes to set. + public void SetResponseBody(byte[] body) + { + if (!WebSession.Request.Locked) + { + throw new Exception("You cannot call this function before request is made to server."); + } + + var response = WebSession.Response; + response.Body = body; + } + + /// + /// Replace the response body with the specified string. + /// + /// The body string to set. + public void SetResponseBodyString(string body) + { + if (!WebSession.Request.Locked) + { + throw new Exception("You cannot call this function before request is made to server."); + } + + var bodyBytes = WebSession.Response.Encoding.GetBytes(body); + + SetResponseBody(bodyBytes); + } + + /// + /// Before request is made to server respond with the specified HTML string to client + /// and ignore the request. + /// + /// HTML content to sent. + /// HTTP response headers. + /// Close the server connection used by request if any? + public void Ok(string html, Dictionary headers = null, + bool closeServerConnection = false) + { + var response = new OkResponse(); + if (headers != null) + { + response.Headers.AddHeaders(headers); + } + + response.HttpVersion = WebSession.Request.HttpVersion; + response.Body = response.Encoding.GetBytes(html ?? string.Empty); + + Respond(response, closeServerConnection); + } + + /// + /// Before request is made to server respond with the specified byte[] to client + /// and ignore the request. + /// + /// The html content bytes. + /// The HTTP headers. + /// Close the server connection used by request if any? + public void Ok(byte[] result, Dictionary headers = null, + bool closeServerConnection = false) + { + var response = new OkResponse(); + response.Headers.AddHeaders(headers); + response.HttpVersion = WebSession.Request.HttpVersion; + response.Body = result; + + Respond(response, closeServerConnection); + } + + /// + /// Before request is made to server  + /// respond with the specified HTML string and the specified status to client. + /// And then ignore the request.  + /// + /// The html content. + /// The HTTP status code. + /// The HTTP headers. + /// Close the server connection used by request if any? + public void GenericResponse(string html, HttpStatusCode status, + Dictionary headers = null, bool closeServerConnection = false) + { + var response = new GenericResponse(status); + response.HttpVersion = WebSession.Request.HttpVersion; + response.Headers.AddHeaders(headers); + response.Body = response.Encoding.GetBytes(html ?? string.Empty); + + Respond(response, closeServerConnection); + } + + /// + /// Before request is made to server respond with the specified byte[], + /// the specified status to client. And then ignore the request. + /// + /// The bytes to sent. + /// The HTTP status code. + /// The HTTP headers. + /// Close the server connection used by request if any? + public void GenericResponse(byte[] result, HttpStatusCode status, + Dictionary headers, bool closeServerConnection = false) + { + var response = new GenericResponse(status); + response.HttpVersion = WebSession.Request.HttpVersion; + response.Headers.AddHeaders(headers); + response.Body = result; + + Respond(response, closeServerConnection); + } + + /// + /// Redirect to provided URL. + /// + /// The URL to redirect. + /// Close the server connection used by request if any? + public void Redirect(string url, bool closeServerConnection = false) + { + var response = new RedirectResponse(); + response.HttpVersion = WebSession.Request.HttpVersion; + response.Headers.AddHeader(KnownHeaders.Location, url); + response.Body = emptyData; + + Respond(response, closeServerConnection); + } + + /// + /// Respond with given response object to client. + /// + /// The response object. + /// Close the server connection used by request if any? + public void Respond(Response response, bool closeServerConnection = false) + { + //request already send/ready to be sent. + if (WebSession.Request.Locked) + { + //response already received from server and ready to be sent to client. + if (WebSession.Response.Locked) + { + throw new Exception("You cannot call this function after response is sent to the client."); + } + + //cleanup original response. + if (closeServerConnection) + { + //no need to cleanup original connection. + //it will be closed any way. + TerminateServerConnection(); + } + + response.SetOriginalHeaders(WebSession.Response); + + //response already received from server but not yet ready to sent to client. + WebSession.Response = response; + WebSession.Response.Locked = true; + } + //request not yet sent/not yet ready to be sent. + else + { + WebSession.Request.Locked = true; + WebSession.Request.CancelRequest = true; + + //set new response. + WebSession.Response = response; + WebSession.Response.Locked = true; + } + + } + + /// + /// Terminate the connection to server at the end of this HTTP request/response session. + /// + public void TerminateServerConnection() + { + WebSession.CloseServerConnection = true; + } + + /// + /// Implement any cleanup here + /// + public override void Dispose() + { + MultipartRequestPartSent = null; + base.Dispose(); + } + } +} diff --git a/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs rename to src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs diff --git a/Titanium.Web.Proxy/EventArguments/TransformationMode.cs b/src/Titanium.Web.Proxy/EventArguments/TransformationMode.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/TransformationMode.cs rename to src/Titanium.Web.Proxy/EventArguments/TransformationMode.cs diff --git a/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs similarity index 100% rename from Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs diff --git a/Titanium.Web.Proxy/ExceptionHandler.cs b/src/Titanium.Web.Proxy/ExceptionHandler.cs similarity index 100% rename from Titanium.Web.Proxy/ExceptionHandler.cs rename to src/Titanium.Web.Proxy/ExceptionHandler.cs diff --git a/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs b/src/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs similarity index 100% rename from Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs rename to src/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs diff --git a/Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs b/src/Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs similarity index 97% rename from Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs rename to src/Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs index 1860711ff..f966330bb 100644 --- a/Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs +++ b/src/Titanium.Web.Proxy/Exceptions/ProxyAuthorizationException.cs @@ -1,37 +1,37 @@ -using System; -using System.Collections.Generic; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Models; - -namespace Titanium.Web.Proxy.Exceptions -{ - /// - /// Proxy authorization exception. - /// - public class ProxyAuthorizationException : ProxyException - { - /// - /// Initializes a new instance of the class. - /// - /// Exception message. - /// The instance containing the event data. - /// Inner exception associated to upstream proxy authorization - /// Http's headers associated - internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException, - IEnumerable headers) : base(message, innerException) - { - Session = session; - Headers = headers; - } - - /// - /// The current session within which this error happened. - /// - public SessionEventArgsBase Session { get; } - - /// - /// Headers associated with the authorization exception. - /// - public IEnumerable Headers { get; } - } -} +using System; +using System.Collections.Generic; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Models; + +namespace Titanium.Web.Proxy.Exceptions +{ + /// + /// Proxy authorization exception. + /// + public class ProxyAuthorizationException : ProxyException + { + /// + /// Initializes a new instance of the class. + /// + /// Exception message. + /// The instance containing the event data. + /// Inner exception associated to upstream proxy authorization + /// Http's headers associated + internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException, + IEnumerable headers) : base(message, innerException) + { + Session = session; + Headers = headers; + } + + /// + /// The current session within which this error happened. + /// + public SessionEventArgsBase Session { get; } + + /// + /// Headers associated with the authorization exception. + /// + public IEnumerable Headers { get; } + } +} diff --git a/Titanium.Web.Proxy/Exceptions/ProxyConnectException.cs b/src/Titanium.Web.Proxy/Exceptions/ProxyConnectException.cs similarity index 100% rename from Titanium.Web.Proxy/Exceptions/ProxyConnectException.cs rename to src/Titanium.Web.Proxy/Exceptions/ProxyConnectException.cs diff --git a/Titanium.Web.Proxy/Exceptions/ProxyException.cs b/src/Titanium.Web.Proxy/Exceptions/ProxyException.cs similarity index 97% rename from Titanium.Web.Proxy/Exceptions/ProxyException.cs rename to src/Titanium.Web.Proxy/Exceptions/ProxyException.cs index 424edf8bc..61696d8d6 100644 --- a/Titanium.Web.Proxy/Exceptions/ProxyException.cs +++ b/src/Titanium.Web.Proxy/Exceptions/ProxyException.cs @@ -1,29 +1,29 @@ -using System; - -namespace Titanium.Web.Proxy.Exceptions -{ - /// - /// Base class exception associated with this proxy server. - /// - public abstract class ProxyException : Exception - { - /// - /// Initializes a new instance of the class. - /// - must be invoked by derived classes' constructors - /// - /// Exception message - protected ProxyException(string message) : base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - must be invoked by derived classes' constructors - /// - /// Excception message - /// Inner exception associated - protected ProxyException(string message, Exception innerException) : base(message, innerException) - { - } - } -} +using System; + +namespace Titanium.Web.Proxy.Exceptions +{ + /// + /// Base class exception associated with this proxy server. + /// + public abstract class ProxyException : Exception + { + /// + /// Initializes a new instance of the class. + /// - must be invoked by derived classes' constructors + /// + /// Exception message + protected ProxyException(string message) : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// - must be invoked by derived classes' constructors + /// + /// Excception message + /// Inner exception associated + protected ProxyException(string message, Exception innerException) : base(message, innerException) + { + } + } +} diff --git a/Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs b/src/Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs similarity index 97% rename from Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs rename to src/Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs index 8aeccaadd..4dd4aa91d 100644 --- a/Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs +++ b/src/Titanium.Web.Proxy/Exceptions/ProxyHttpException.cs @@ -1,31 +1,31 @@ -using System; -using Titanium.Web.Proxy.EventArguments; - -namespace Titanium.Web.Proxy.Exceptions -{ - /// - /// Proxy HTTP exception. - /// - public class ProxyHttpException : ProxyException - { - /// - /// Initializes a new instance of the class. - /// - /// Message for this exception - /// Associated inner exception - /// Instance of associated to the exception - internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base( - message, innerException) - { - SessionEventArgs = sessionEventArgs; - } - - /// - /// Gets session info associated to the exception. - /// - /// - /// This object properties should not be edited. - /// - public SessionEventArgs SessionEventArgs { get; } - } -} +using System; +using Titanium.Web.Proxy.EventArguments; + +namespace Titanium.Web.Proxy.Exceptions +{ + /// + /// Proxy HTTP exception. + /// + public class ProxyHttpException : ProxyException + { + /// + /// Initializes a new instance of the class. + /// + /// Message for this exception + /// Associated inner exception + /// Instance of associated to the exception + internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base( + message, innerException) + { + SessionEventArgs = sessionEventArgs; + } + + /// + /// Gets session info associated to the exception. + /// + /// + /// This object properties should not be edited. + /// + public SessionEventArgs SessionEventArgs { get; } + } +} diff --git a/Titanium.Web.Proxy/Exceptions/ServerConnectionException.cs b/src/Titanium.Web.Proxy/Exceptions/ServerConnectionException.cs similarity index 100% rename from Titanium.Web.Proxy/Exceptions/ServerConnectionException.cs rename to src/Titanium.Web.Proxy/Exceptions/ServerConnectionException.cs diff --git a/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs similarity index 100% rename from Titanium.Web.Proxy/ExplicitClientHandler.cs rename to src/Titanium.Web.Proxy/ExplicitClientHandler.cs diff --git a/Titanium.Web.Proxy/Extensions/FuncExtensions.cs b/src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs similarity index 100% rename from Titanium.Web.Proxy/Extensions/FuncExtensions.cs rename to src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs diff --git a/Titanium.Web.Proxy/Extensions/SslExtensions.cs b/src/Titanium.Web.Proxy/Extensions/SslExtensions.cs similarity index 100% rename from Titanium.Web.Proxy/Extensions/SslExtensions.cs rename to src/Titanium.Web.Proxy/Extensions/SslExtensions.cs diff --git a/Titanium.Web.Proxy/Extensions/StreamExtensions.cs b/src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs similarity index 100% rename from Titanium.Web.Proxy/Extensions/StreamExtensions.cs rename to src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs diff --git a/Titanium.Web.Proxy/Extensions/StringExtensions.cs b/src/Titanium.Web.Proxy/Extensions/StringExtensions.cs similarity index 100% rename from Titanium.Web.Proxy/Extensions/StringExtensions.cs rename to src/Titanium.Web.Proxy/Extensions/StringExtensions.cs diff --git a/Titanium.Web.Proxy/Extensions/TcpExtensions.cs b/src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs similarity index 100% rename from Titanium.Web.Proxy/Extensions/TcpExtensions.cs rename to src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs diff --git a/Titanium.Web.Proxy/Helpers/HttpHelper.cs b/src/Titanium.Web.Proxy/Helpers/HttpHelper.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/HttpHelper.cs rename to src/Titanium.Web.Proxy/Helpers/HttpHelper.cs diff --git a/Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs b/src/Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs rename to src/Titanium.Web.Proxy/Helpers/HttpRequestWriter.cs diff --git a/Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs b/src/Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs rename to src/Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs diff --git a/Titanium.Web.Proxy/Helpers/HttpWriter.cs b/src/Titanium.Web.Proxy/Helpers/HttpWriter.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/HttpWriter.cs rename to src/Titanium.Web.Proxy/Helpers/HttpWriter.cs diff --git a/Titanium.Web.Proxy/Helpers/NativeMethods.SystemProxy.cs b/src/Titanium.Web.Proxy/Helpers/NativeMethods.SystemProxy.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/NativeMethods.SystemProxy.cs rename to src/Titanium.Web.Proxy/Helpers/NativeMethods.SystemProxy.cs diff --git a/Titanium.Web.Proxy/Helpers/NativeMethods.Tcp.cs b/src/Titanium.Web.Proxy/Helpers/NativeMethods.Tcp.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/NativeMethods.Tcp.cs rename to src/Titanium.Web.Proxy/Helpers/NativeMethods.Tcp.cs diff --git a/Titanium.Web.Proxy/Helpers/Network.cs b/src/Titanium.Web.Proxy/Helpers/Network.cs similarity index 96% rename from Titanium.Web.Proxy/Helpers/Network.cs rename to src/Titanium.Web.Proxy/Helpers/Network.cs index b0949ff5b..ee9bc9126 100644 --- a/Titanium.Web.Proxy/Helpers/Network.cs +++ b/src/Titanium.Web.Proxy/Helpers/Network.cs @@ -1,73 +1,73 @@ -using System.Linq; -using System.Net; -using System.Net.Sockets; - -namespace Titanium.Web.Proxy.Helpers -{ - internal class NetworkHelper - { - /// - /// Adapated from below link - /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost - /// - /// - /// - internal static bool IsLocalIpAddress(IPAddress address) - { - if (IPAddress.IsLoopback(address)) - { - return true; - } - - // get local IP addresses - var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); - - // test if any host IP equals to any local IP or to localhost - return localIPs.Contains(address); - } - - internal static bool IsLocalIpAddress(string hostName) - { - hostName = hostName.ToLower(); - - if (hostName == "127.0.0.1" - || hostName == "localhost") - { - return true; - } - - var localhostDnsName = Dns.GetHostName().ToLower(); - - //if hostname matches current machine DNS name - if (hostName == localhostDnsName) - { - return true; - } - - var isLocalhost = false; - IPHostEntry hostEntry = null; - - //check if parsable to an IP Address - if (IPAddress.TryParse(hostName, out var ipAddress)) - { - hostEntry = Dns.GetHostEntry(localhostDnsName); - isLocalhost = hostEntry.AddressList.Any(x => x.Equals(ipAddress)); - } - - if (!isLocalhost) - { - try - { - hostEntry = Dns.GetHostEntry(hostName); - isLocalhost = hostEntry.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals)); - } - catch (SocketException) - { - } - } - - - return isLocalhost; - } - } -} +using System.Linq; +using System.Net; +using System.Net.Sockets; + +namespace Titanium.Web.Proxy.Helpers +{ + internal class NetworkHelper + { + /// + /// Adapated from below link + /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost + /// + /// + /// + internal static bool IsLocalIpAddress(IPAddress address) + { + if (IPAddress.IsLoopback(address)) + { + return true; + } + + // get local IP addresses + var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); + + // test if any host IP equals to any local IP or to localhost + return localIPs.Contains(address); + } + + internal static bool IsLocalIpAddress(string hostName) + { + hostName = hostName.ToLower(); + + if (hostName == "127.0.0.1" + || hostName == "localhost") + { + return true; + } + + var localhostDnsName = Dns.GetHostName().ToLower(); + + //if hostname matches current machine DNS name + if (hostName == localhostDnsName) + { + return true; + } + + var isLocalhost = false; + IPHostEntry hostEntry = null; + + //check if parsable to an IP Address + if (IPAddress.TryParse(hostName, out var ipAddress)) + { + hostEntry = Dns.GetHostEntry(localhostDnsName); + isLocalhost = hostEntry.AddressList.Any(x => x.Equals(ipAddress)); + } + + if (!isLocalhost) + { + try + { + hostEntry = Dns.GetHostEntry(hostName); + isLocalhost = hostEntry.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals)); + } + catch (SocketException) + { + } + } + + + return isLocalhost; + } + } +} diff --git a/Titanium.Web.Proxy/Helpers/ProxyInfo.cs b/src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/ProxyInfo.cs rename to src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs diff --git a/Titanium.Web.Proxy/Helpers/Ref.cs b/src/Titanium.Web.Proxy/Helpers/Ref.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/Ref.cs rename to src/Titanium.Web.Proxy/Helpers/Ref.cs diff --git a/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/RunTime.cs rename to src/Titanium.Web.Proxy/Helpers/RunTime.cs diff --git a/Titanium.Web.Proxy/Helpers/SystemProxy.cs b/src/Titanium.Web.Proxy/Helpers/SystemProxy.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/SystemProxy.cs rename to src/Titanium.Web.Proxy/Helpers/SystemProxy.cs diff --git a/Titanium.Web.Proxy/Helpers/TcpHelper.cs b/src/Titanium.Web.Proxy/Helpers/TcpHelper.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/TcpHelper.cs rename to src/Titanium.Web.Proxy/Helpers/TcpHelper.cs diff --git a/Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs b/src/Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs rename to src/Titanium.Web.Proxy/Helpers/WinHttp/NativeMethods.WinHttp.cs diff --git a/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs rename to src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpHandle.cs diff --git a/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs similarity index 100% rename from Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs rename to src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs diff --git a/Titanium.Web.Proxy/Http/ConnectRequest.cs b/src/Titanium.Web.Proxy/Http/ConnectRequest.cs similarity index 100% rename from Titanium.Web.Proxy/Http/ConnectRequest.cs rename to src/Titanium.Web.Proxy/Http/ConnectRequest.cs diff --git a/Titanium.Web.Proxy/Http/ConnectResponse.cs b/src/Titanium.Web.Proxy/Http/ConnectResponse.cs similarity index 100% rename from Titanium.Web.Proxy/Http/ConnectResponse.cs rename to src/Titanium.Web.Proxy/Http/ConnectResponse.cs diff --git a/Titanium.Web.Proxy/Http/HeaderCollection.cs b/src/Titanium.Web.Proxy/Http/HeaderCollection.cs similarity index 100% rename from Titanium.Web.Proxy/Http/HeaderCollection.cs rename to src/Titanium.Web.Proxy/Http/HeaderCollection.cs diff --git a/Titanium.Web.Proxy/Http/HeaderParser.cs b/src/Titanium.Web.Proxy/Http/HeaderParser.cs similarity index 100% rename from Titanium.Web.Proxy/Http/HeaderParser.cs rename to src/Titanium.Web.Proxy/Http/HeaderParser.cs diff --git a/Titanium.Web.Proxy/Http/HttpWebClient.cs b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs similarity index 97% rename from Titanium.Web.Proxy/Http/HttpWebClient.cs rename to src/Titanium.Web.Proxy/Http/HttpWebClient.cs index ab39d3bc4..4813d6fab 100644 --- a/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -1,251 +1,251 @@ -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Titanium.Web.Proxy.Exceptions; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network.Tcp; -using Titanium.Web.Proxy.Shared; - -namespace Titanium.Web.Proxy.Http -{ - /// - /// Used to communicate with the server over HTTP(S) - /// - public class HttpWebClient - { - internal HttpWebClient(Request request = null, Response response = null) - { - Request = request ?? new Request(); - Response = response ?? new Response(); - } - - /// - /// Connection to server - /// - internal TcpServerConnection ServerConnection { get; set; } - - /// - /// Should we close the server connection at the end of this HTTP request/response session. - /// - internal bool CloseServerConnection { get; set; } - - /// - /// Stores internal data for the session. - /// - internal InternalDataStore Data { get; } = new InternalDataStore(); - - /// - /// Gets or sets the user data. - /// - public object UserData { get; set; } - - /// - /// Override UpStreamEndPoint for this request; Local NIC via request is made - /// - public IPEndPoint UpStreamEndPoint { get; set; } - - /// - /// Headers passed with Connect. - /// - public ConnectRequest ConnectRequest { get; internal set; } - - /// - /// Web Request. - /// - public Request Request { get; } - - /// - /// Web Response. - /// - public Response Response { get; internal set; } - - /// - /// PID of the process that is created the current session when client is running in this machine - /// If client is remote then this will return - /// - public Lazy ProcessId { get; internal set; } - - /// - /// Is Https? - /// - public bool IsHttps => Request.IsHttps; - - /// - /// Set the tcp connection to server used by this webclient - /// - /// Instance of - internal void SetConnection(TcpServerConnection serverConnection) - { - serverConnection.LastAccess = DateTime.Now; - ServerConnection = serverConnection; - } - - /// - /// Prepare and send the http(s) request - /// - /// - internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent, - CancellationToken cancellationToken) - { - var upstreamProxy = ServerConnection.UpStreamProxy; - - bool useUpstreamProxy = upstreamProxy != null && ServerConnection.IsHttps == false; - - var writer = ServerConnection.StreamWriter; - - // prepare the request & headers - await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, - useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery, - Request.HttpVersion), cancellationToken); - - var headerBuilder = new StringBuilder(); - - // Send Authentication to Upstream proxy if needed - if (!isTransparent && upstreamProxy != null - && ServerConnection.IsHttps == false - && !string.IsNullOrEmpty(upstreamProxy.UserName) - && upstreamProxy.Password != null) - { - headerBuilder.Append($"{HttpHeader.ProxyConnectionKeepAlive}{ProxyConstants.NewLine}"); - headerBuilder.Append($"{HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)}{ProxyConstants.NewLine}"); - } - - // write request headers - foreach (var header in Request.Headers) - { - if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization) - { - headerBuilder.Append($"{header}{ProxyConstants.NewLine}"); - } - } - - headerBuilder.Append(ProxyConstants.NewLine); - - await writer.WriteAsync(headerBuilder.ToString(), cancellationToken); - - if (enable100ContinueBehaviour) - { - if (Request.ExpectContinue) - { - string httpStatus; - try - { - httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); - if (httpStatus == null) - { - throw new ServerConnectionException("Server connection was closed."); - } - } - catch (Exception e) when (!(e is ServerConnectionException)) - { - throw new ServerConnectionException("Server connection was closed."); - } - - Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, - out string responseStatusDescription); - - // find if server is willing for expect continue - if (responseStatusCode == (int)HttpStatusCode.Continue - && responseStatusDescription.EqualsIgnoreCase("continue")) - { - Request.Is100Continue = true; - await ServerConnection.Stream.ReadLineAsync(cancellationToken); - } - else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed - && responseStatusDescription.EqualsIgnoreCase("expectation failed")) - { - Request.ExpectationFailed = true; - await ServerConnection.Stream.ReadLineAsync(cancellationToken); - } - } - } - } - - /// - /// Receive and parse the http response from server - /// - /// - internal async Task ReceiveResponse(CancellationToken cancellationToken) - { - // return if this is already read - if (Response.StatusCode != 0) - { - return; - } - - string httpStatus; - try - { - httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); - if (httpStatus == null) - { - throw new ServerConnectionException("Server connection was closed."); - } - } - catch (Exception e) when (!(e is ServerConnectionException)) - { - throw new ServerConnectionException("Server connection was closed."); - } - - if (httpStatus == string.Empty) - { - httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); - } - - Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); - - Response.HttpVersion = version; - Response.StatusCode = statusCode; - Response.StatusDescription = statusDescription; - - // For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request - if (Response.StatusCode == (int)HttpStatusCode.Continue - && Response.StatusDescription.EqualsIgnoreCase("continue")) - { - // Read the next line after 100-continue - Response.Is100Continue = true; - Response.StatusCode = 0; - await ServerConnection.Stream.ReadLineAsync(cancellationToken); - - // now receive response - await ReceiveResponse(cancellationToken); - return; - } - - if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed - && Response.StatusDescription.EqualsIgnoreCase("expectation failed")) - { - // read next line after expectation failed response - Response.ExpectationFailed = true; - Response.StatusCode = 0; - await ServerConnection.Stream.ReadLineAsync(cancellationToken); - - // now receive response - await ReceiveResponse(cancellationToken); - return; - } - - // Read the response headers in to unique and non-unique header collections - await HeaderParser.ReadHeaders(ServerConnection.Stream, Response.Headers, cancellationToken); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - internal void FinishSession() - { - ServerConnection = null; - - ConnectRequest?.FinishSession(); - Request?.FinishSession(); - Response?.FinishSession(); - - Data.Clear(); - UserData = null; - } - } -} +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Titanium.Web.Proxy.Exceptions; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network.Tcp; +using Titanium.Web.Proxy.Shared; + +namespace Titanium.Web.Proxy.Http +{ + /// + /// Used to communicate with the server over HTTP(S) + /// + public class HttpWebClient + { + internal HttpWebClient(Request request = null, Response response = null) + { + Request = request ?? new Request(); + Response = response ?? new Response(); + } + + /// + /// Connection to server + /// + internal TcpServerConnection ServerConnection { get; set; } + + /// + /// Should we close the server connection at the end of this HTTP request/response session. + /// + internal bool CloseServerConnection { get; set; } + + /// + /// Stores internal data for the session. + /// + internal InternalDataStore Data { get; } = new InternalDataStore(); + + /// + /// Gets or sets the user data. + /// + public object UserData { get; set; } + + /// + /// Override UpStreamEndPoint for this request; Local NIC via request is made + /// + public IPEndPoint UpStreamEndPoint { get; set; } + + /// + /// Headers passed with Connect. + /// + public ConnectRequest ConnectRequest { get; internal set; } + + /// + /// Web Request. + /// + public Request Request { get; } + + /// + /// Web Response. + /// + public Response Response { get; internal set; } + + /// + /// PID of the process that is created the current session when client is running in this machine + /// If client is remote then this will return + /// + public Lazy ProcessId { get; internal set; } + + /// + /// Is Https? + /// + public bool IsHttps => Request.IsHttps; + + /// + /// Set the tcp connection to server used by this webclient + /// + /// Instance of + internal void SetConnection(TcpServerConnection serverConnection) + { + serverConnection.LastAccess = DateTime.Now; + ServerConnection = serverConnection; + } + + /// + /// Prepare and send the http(s) request + /// + /// + internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent, + CancellationToken cancellationToken) + { + var upstreamProxy = ServerConnection.UpStreamProxy; + + bool useUpstreamProxy = upstreamProxy != null && ServerConnection.IsHttps == false; + + var writer = ServerConnection.StreamWriter; + + // prepare the request & headers + await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, + useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery, + Request.HttpVersion), cancellationToken); + + var headerBuilder = new StringBuilder(); + + // Send Authentication to Upstream proxy if needed + if (!isTransparent && upstreamProxy != null + && ServerConnection.IsHttps == false + && !string.IsNullOrEmpty(upstreamProxy.UserName) + && upstreamProxy.Password != null) + { + headerBuilder.Append($"{HttpHeader.ProxyConnectionKeepAlive}{ProxyConstants.NewLine}"); + headerBuilder.Append($"{HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)}{ProxyConstants.NewLine}"); + } + + // write request headers + foreach (var header in Request.Headers) + { + if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization) + { + headerBuilder.Append($"{header}{ProxyConstants.NewLine}"); + } + } + + headerBuilder.Append(ProxyConstants.NewLine); + + await writer.WriteAsync(headerBuilder.ToString(), cancellationToken); + + if (enable100ContinueBehaviour) + { + if (Request.ExpectContinue) + { + string httpStatus; + try + { + httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); + if (httpStatus == null) + { + throw new ServerConnectionException("Server connection was closed."); + } + } + catch (Exception e) when (!(e is ServerConnectionException)) + { + throw new ServerConnectionException("Server connection was closed."); + } + + Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, + out string responseStatusDescription); + + // find if server is willing for expect continue + if (responseStatusCode == (int)HttpStatusCode.Continue + && responseStatusDescription.EqualsIgnoreCase("continue")) + { + Request.Is100Continue = true; + await ServerConnection.Stream.ReadLineAsync(cancellationToken); + } + else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed + && responseStatusDescription.EqualsIgnoreCase("expectation failed")) + { + Request.ExpectationFailed = true; + await ServerConnection.Stream.ReadLineAsync(cancellationToken); + } + } + } + } + + /// + /// Receive and parse the http response from server + /// + /// + internal async Task ReceiveResponse(CancellationToken cancellationToken) + { + // return if this is already read + if (Response.StatusCode != 0) + { + return; + } + + string httpStatus; + try + { + httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); + if (httpStatus == null) + { + throw new ServerConnectionException("Server connection was closed."); + } + } + catch (Exception e) when (!(e is ServerConnectionException)) + { + throw new ServerConnectionException("Server connection was closed."); + } + + if (httpStatus == string.Empty) + { + httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken); + } + + Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); + + Response.HttpVersion = version; + Response.StatusCode = statusCode; + Response.StatusDescription = statusDescription; + + // For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request + if (Response.StatusCode == (int)HttpStatusCode.Continue + && Response.StatusDescription.EqualsIgnoreCase("continue")) + { + // Read the next line after 100-continue + Response.Is100Continue = true; + Response.StatusCode = 0; + await ServerConnection.Stream.ReadLineAsync(cancellationToken); + + // now receive response + await ReceiveResponse(cancellationToken); + return; + } + + if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed + && Response.StatusDescription.EqualsIgnoreCase("expectation failed")) + { + // read next line after expectation failed response + Response.ExpectationFailed = true; + Response.StatusCode = 0; + await ServerConnection.Stream.ReadLineAsync(cancellationToken); + + // now receive response + await ReceiveResponse(cancellationToken); + return; + } + + // Read the response headers in to unique and non-unique header collections + await HeaderParser.ReadHeaders(ServerConnection.Stream, Response.Headers, cancellationToken); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + internal void FinishSession() + { + ServerConnection = null; + + ConnectRequest?.FinishSession(); + Request?.FinishSession(); + Response?.FinishSession(); + + Data.Clear(); + UserData = null; + } + } +} diff --git a/Titanium.Web.Proxy/Http/InternalDataStore.cs b/src/Titanium.Web.Proxy/Http/InternalDataStore.cs similarity index 100% rename from Titanium.Web.Proxy/Http/InternalDataStore.cs rename to src/Titanium.Web.Proxy/Http/InternalDataStore.cs diff --git a/Titanium.Web.Proxy/Http/KnownHeaders.cs b/src/Titanium.Web.Proxy/Http/KnownHeaders.cs similarity index 100% rename from Titanium.Web.Proxy/Http/KnownHeaders.cs rename to src/Titanium.Web.Proxy/Http/KnownHeaders.cs diff --git a/Titanium.Web.Proxy/Http/Request.cs b/src/Titanium.Web.Proxy/Http/Request.cs similarity index 100% rename from Titanium.Web.Proxy/Http/Request.cs rename to src/Titanium.Web.Proxy/Http/Request.cs diff --git a/Titanium.Web.Proxy/Http/RequestResponseBase.cs b/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs similarity index 100% rename from Titanium.Web.Proxy/Http/RequestResponseBase.cs rename to src/Titanium.Web.Proxy/Http/RequestResponseBase.cs diff --git a/Titanium.Web.Proxy/Http/Response.cs b/src/Titanium.Web.Proxy/Http/Response.cs similarity index 100% rename from Titanium.Web.Proxy/Http/Response.cs rename to src/Titanium.Web.Proxy/Http/Response.cs diff --git a/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs b/src/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs similarity index 100% rename from Titanium.Web.Proxy/Http/Responses/GenericResponse.cs rename to src/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs diff --git a/Titanium.Web.Proxy/Http/Responses/OkResponse.cs b/src/Titanium.Web.Proxy/Http/Responses/OkResponse.cs similarity index 100% rename from Titanium.Web.Proxy/Http/Responses/OkResponse.cs rename to src/Titanium.Web.Proxy/Http/Responses/OkResponse.cs diff --git a/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs b/src/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs similarity index 100% rename from Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs rename to src/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/Decoder.cs b/src/Titanium.Web.Proxy/Http2/Hpack/Decoder.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/Decoder.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/Decoder.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs b/src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/DynamicTable.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs b/src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/Encoder.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs b/src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/HpackUtil.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs b/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/HuffmanDecoder.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/HuffmanEncoder.cs b/src/Titanium.Web.Proxy/Http2/Hpack/HuffmanEncoder.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/HuffmanEncoder.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/HuffmanEncoder.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/IHeaderListener.cs b/src/Titanium.Web.Proxy/Http2/Hpack/IHeaderListener.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/IHeaderListener.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/IHeaderListener.cs diff --git a/Titanium.Web.Proxy/Http2/Hpack/StaticTable.cs b/src/Titanium.Web.Proxy/Http2/Hpack/StaticTable.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Hpack/StaticTable.cs rename to src/Titanium.Web.Proxy/Http2/Hpack/StaticTable.cs diff --git a/Titanium.Web.Proxy/Http2/Http2Helper.cs b/src/Titanium.Web.Proxy/Http2/Http2Helper.cs similarity index 100% rename from Titanium.Web.Proxy/Http2/Http2Helper.cs rename to src/Titanium.Web.Proxy/Http2/Http2Helper.cs diff --git a/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs similarity index 100% rename from Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs rename to src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs diff --git a/Titanium.Web.Proxy/Models/ExternalProxy.cs b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs similarity index 96% rename from Titanium.Web.Proxy/Models/ExternalProxy.cs rename to src/Titanium.Web.Proxy/Models/ExternalProxy.cs index 7d61d8e26..865fc4bc9 100644 --- a/Titanium.Web.Proxy/Models/ExternalProxy.cs +++ b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs @@ -1,91 +1,91 @@ -using System; -using System.Net; - -namespace Titanium.Web.Proxy.Models -{ - /// - /// An upstream proxy this proxy uses if any. - /// - public class ExternalProxy - { - private static readonly Lazy defaultCredentials = - new Lazy(() => CredentialCache.DefaultNetworkCredentials); - - private string password; - - private string userName; - - /// - /// Use default windows credentials? - /// - public bool UseDefaultCredentials { get; set; } - - /// - /// Bypass this proxy for connections to localhost? - /// - public bool BypassLocalhost { get; set; } - - /// - /// Username. - /// - public string UserName - { - get => UseDefaultCredentials ? defaultCredentials.Value.UserName : userName; - set - { - userName = value; - - if (defaultCredentials.Value.UserName != userName) - { - UseDefaultCredentials = false; - } - } - } - - /// - /// Password. - /// - public string Password - { - get => UseDefaultCredentials ? defaultCredentials.Value.Password : password; - set - { - password = value; - - if (defaultCredentials.Value.Password != password) - { - UseDefaultCredentials = false; - } - } - } - - /// - /// Host name. - /// - public string HostName { get; set; } - - /// - /// Port. - /// - public int Port { get; set; } - - /// - /// Get cache key for Tcp connection cahe. - /// - /// - internal string GetCacheKey() - { - return $"{HostName}-{Port}" + (UseDefaultCredentials ? $"-{UserName}-{Password}" : string.Empty); - } - - /// - /// returns data in Hostname:port format. - /// - /// - public override string ToString() - { - return $"{HostName}:{Port}"; - } - - } -} +using System; +using System.Net; + +namespace Titanium.Web.Proxy.Models +{ + /// + /// An upstream proxy this proxy uses if any. + /// + public class ExternalProxy + { + private static readonly Lazy defaultCredentials = + new Lazy(() => CredentialCache.DefaultNetworkCredentials); + + private string password; + + private string userName; + + /// + /// Use default windows credentials? + /// + public bool UseDefaultCredentials { get; set; } + + /// + /// Bypass this proxy for connections to localhost? + /// + public bool BypassLocalhost { get; set; } + + /// + /// Username. + /// + public string UserName + { + get => UseDefaultCredentials ? defaultCredentials.Value.UserName : userName; + set + { + userName = value; + + if (defaultCredentials.Value.UserName != userName) + { + UseDefaultCredentials = false; + } + } + } + + /// + /// Password. + /// + public string Password + { + get => UseDefaultCredentials ? defaultCredentials.Value.Password : password; + set + { + password = value; + + if (defaultCredentials.Value.Password != password) + { + UseDefaultCredentials = false; + } + } + } + + /// + /// Host name. + /// + public string HostName { get; set; } + + /// + /// Port. + /// + public int Port { get; set; } + + /// + /// Get cache key for Tcp connection cahe. + /// + /// + internal string GetCacheKey() + { + return $"{HostName}-{Port}" + (UseDefaultCredentials ? $"-{UserName}-{Password}" : string.Empty); + } + + /// + /// returns data in Hostname:port format. + /// + /// + public override string ToString() + { + return $"{HostName}:{Port}"; + } + + } +} diff --git a/Titanium.Web.Proxy/Models/HttpHeader.cs b/src/Titanium.Web.Proxy/Models/HttpHeader.cs similarity index 100% rename from Titanium.Web.Proxy/Models/HttpHeader.cs rename to src/Titanium.Web.Proxy/Models/HttpHeader.cs diff --git a/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs b/src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs similarity index 100% rename from Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs rename to src/Titanium.Web.Proxy/Models/ProxyAuthenticationContext.cs diff --git a/Titanium.Web.Proxy/Models/ProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/ProxyEndPoint.cs similarity index 100% rename from Titanium.Web.Proxy/Models/ProxyEndPoint.cs rename to src/Titanium.Web.Proxy/Models/ProxyEndPoint.cs diff --git a/Titanium.Web.Proxy/Models/ProxyProtocolType.cs b/src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs similarity index 100% rename from Titanium.Web.Proxy/Models/ProxyProtocolType.cs rename to src/Titanium.Web.Proxy/Models/ProxyProtocolType.cs diff --git a/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs similarity index 100% rename from Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs rename to src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs diff --git a/Titanium.Web.Proxy/Network/CachedCertificate.cs b/src/Titanium.Web.Proxy/Network/CachedCertificate.cs similarity index 100% rename from Titanium.Web.Proxy/Network/CachedCertificate.cs rename to src/Titanium.Web.Proxy/Network/CachedCertificate.cs diff --git a/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs b/src/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs similarity index 100% rename from Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs rename to src/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs diff --git a/Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs b/src/Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs similarity index 100% rename from Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs rename to src/Titanium.Web.Proxy/Network/Certificate/ICertificateMaker.cs diff --git a/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs b/src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs similarity index 100% rename from Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs rename to src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs diff --git a/Titanium.Web.Proxy/Network/CertificateManager.cs b/src/Titanium.Web.Proxy/Network/CertificateManager.cs similarity index 100% rename from Titanium.Web.Proxy/Network/CertificateManager.cs rename to src/Titanium.Web.Proxy/Network/CertificateManager.cs diff --git a/Titanium.Web.Proxy/Network/DebugCustomBufferedStream.cs b/src/Titanium.Web.Proxy/Network/DebugCustomBufferedStream.cs similarity index 100% rename from Titanium.Web.Proxy/Network/DebugCustomBufferedStream.cs rename to src/Titanium.Web.Proxy/Network/DebugCustomBufferedStream.cs diff --git a/Titanium.Web.Proxy/Network/ProxyClient.cs b/src/Titanium.Web.Proxy/Network/ProxyClient.cs similarity index 100% rename from Titanium.Web.Proxy/Network/ProxyClient.cs rename to src/Titanium.Web.Proxy/Network/ProxyClient.cs diff --git a/Titanium.Web.Proxy/Network/RetryPolicy.cs b/src/Titanium.Web.Proxy/Network/RetryPolicy.cs similarity index 100% rename from Titanium.Web.Proxy/Network/RetryPolicy.cs rename to src/Titanium.Web.Proxy/Network/RetryPolicy.cs diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs similarity index 100% rename from Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs rename to src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs similarity index 97% rename from Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs rename to src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index d5e3366d7..2f004e3f2 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -1,546 +1,546 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Security; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using StreamExtended.Network; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Helpers; -using Titanium.Web.Proxy.Http; -using Titanium.Web.Proxy.Models; - -namespace Titanium.Web.Proxy.Network.Tcp -{ - /// - /// A class that manages Tcp Connection to server used by this proxy server. - /// - internal class TcpConnectionFactory : IDisposable - { - //Tcp server connection pool cache - private readonly ConcurrentDictionary> cache - = new ConcurrentDictionary>(); - - //Tcp connections waiting to be disposed by cleanup task - private readonly ConcurrentBag disposalBag = - new ConcurrentBag(); - - //cache object race operations lock - private readonly SemaphoreSlim @lock = new SemaphoreSlim(1); - - private volatile bool runCleanUpTask = true; - - internal TcpConnectionFactory(ProxyServer server) - { - this.server = server; - Task.Run(async () => await clearOutdatedConnections()); - } - - internal ProxyServer server { get; set; } - - internal string GetConnectionCacheKey(string remoteHostName, int remotePort, - bool isHttps, List applicationProtocols, - ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy) - { - //http version is ignored since its an application level decision b/w HTTP 1.0/1.1 - //also when doing connect request MS Edge browser sends http 1.0 but uses 1.1 after server sends 1.1 its response. - //That can create cache miss for same server connection unneccessarily expecially when prefetcing with Connect. - //http version 2 is separated using applicationProtocols below. - var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" + - //when creating Tcp client isConnect won't matter - $"{isHttps}-"); - if (applicationProtocols != null) - { - foreach (var protocol in applicationProtocols.OrderBy(x => x)) - { - cacheKeyBuilder.Append($"{protocol}-"); - } - } - - cacheKeyBuilder.Append(upStreamEndPoint != null - ? $"{upStreamEndPoint.Address}-{upStreamEndPoint.Port}-" - : string.Empty); - cacheKeyBuilder.Append(externalProxy != null ? $"{externalProxy.GetCacheKey()}-" : string.Empty); - - return cacheKeyBuilder.ToString(); - - } - - /// - /// Gets the connection cache key. - /// - /// The session event arguments. - /// - /// - internal async Task GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args, - SslApplicationProtocol applicationProtocol) - { - List applicationProtocols = null; - if (applicationProtocol != default) - { - applicationProtocols = new List { applicationProtocol }; - } - - ExternalProxy customUpStreamProxy = null; - - bool isHttps = args.IsHttps; - if (server.GetCustomUpStreamProxyFunc != null) - { - customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); - } - - args.CustomUpStreamProxyUsed = customUpStreamProxy; - - return GetConnectionCacheKey( - args.WebSession.Request.RequestUri.Host, - args.WebSession.Request.RequestUri.Port, - isHttps, applicationProtocols, - server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, - customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy)); - } - - - /// - /// Create a server connection. - /// - /// The session event arguments. - /// Is this a CONNECT request. - /// - /// The cancellation token for this async task. - /// - internal Task GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, - SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken) - { - List applicationProtocols = null; - if (applicationProtocol != default) - { - applicationProtocols = new List { applicationProtocol }; - } - - return GetServerConnection(server, args, isConnect, applicationProtocols, noCache, cancellationToken); - } - - /// - /// Create a server connection. - /// - /// The session event arguments. - /// Is this a CONNECT request. - /// - /// The cancellation token for this async task. - /// - internal async Task GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, - List applicationProtocols, bool noCache, CancellationToken cancellationToken) - { - ExternalProxy customUpStreamProxy = null; - - bool isHttps = args.IsHttps; - if (server.GetCustomUpStreamProxyFunc != null) - { - customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); - } - - args.CustomUpStreamProxyUsed = customUpStreamProxy; - - return await GetServerConnection( - args.WebSession.Request.RequestUri.Host, - args.WebSession.Request.RequestUri.Port, - args.WebSession.Request.HttpVersion, - isHttps, applicationProtocols, isConnect, - server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, - customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy), - noCache, cancellationToken); - } - /// - /// Gets a TCP connection to server from connection pool. - /// - /// The remote hostname. - /// The remote port. - /// The http version to use. - /// Is this a HTTPS request. - /// The list of HTTPS application level protocol to negotiate if needed. - /// Is this a CONNECT request. - /// The current ProxyServer instance. - /// The local upstream endpoint to make request via. - /// The external proxy to make request via. - /// Not from cache/create new connection. - /// The cancellation token for this async task. - /// - internal async Task GetServerConnection(string remoteHostName, int remotePort, - Version httpVersion, bool isHttps, List applicationProtocols, bool isConnect, - ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, - bool noCache, CancellationToken cancellationToken) - { - var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort, - isHttps, applicationProtocols, - proxyServer, upStreamEndPoint, externalProxy); - - if (proxyServer.EnableConnectionPool && !noCache) - { - if (cache.TryGetValue(cacheKey, out var existingConnections)) - { - while (existingConnections.Count > 0) - { - if (existingConnections.TryDequeue(out var recentConnection)) - { - //+3 seconds for potential delay after getting connection - var cutOff = DateTime.Now.AddSeconds(-1 * proxyServer.ConnectionTimeOutSeconds + 3); - - if (recentConnection.LastAccess > cutOff - && recentConnection.TcpClient.IsGoodConnection()) - { - return recentConnection; - } - - disposalBag.Add(recentConnection); - } - } - } - } - - var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, - applicationProtocols, isConnect, proxyServer, upStreamEndPoint, externalProxy, cancellationToken); - - connection.CacheKey = cacheKey; - - return connection; - } - - /// - /// Creates a TCP connection to server - /// - /// The remote hostname. - /// The remote port. - /// The http version to use. - /// Is this a HTTPS request. - /// The list of HTTPS application level protocol to negotiate if needed. - /// Is this a CONNECT request. - /// The current ProxyServer instance. - /// The local upstream endpoint to make request via. - /// The external proxy to make request via. - /// The cancellation token for this async task. - /// - private async Task createServerConnection(string remoteHostName, int remotePort, - Version httpVersion, bool isHttps, List applicationProtocols, bool isConnect, - ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, - CancellationToken cancellationToken) - { - //deny connection to proxy end points to avoid infinite connection loop. - if (server.ProxyEndPoints.Any(x => x.Port == remotePort) - && NetworkHelper.IsLocalIpAddress(remoteHostName)) - { - throw new Exception($"A client is making HTTP request to one of the listening ports of this proxy {remoteHostName}:{remotePort}"); - } - - if (externalProxy != null) - { - if (server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port) - && NetworkHelper.IsLocalIpAddress(externalProxy.HostName)) - { - throw new Exception($"A client is making HTTP request via external proxy to one of the listening ports of this proxy {remoteHostName}:{remotePort}"); - } - } - - bool useUpstreamProxy = false; - - // check if external proxy is set for HTTP/HTTPS - if (externalProxy != null && - !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort)) - { - useUpstreamProxy = true; - - // check if we need to ByPass - if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName)) - { - useUpstreamProxy = false; - } - } - - TcpClient tcpClient = null; - CustomBufferedStream stream = null; - - SslApplicationProtocol negotiatedApplicationProtocol = default; - - try - { - tcpClient = new TcpClient(upStreamEndPoint) - { - ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, - SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, - SendBufferSize = proxyServer.BufferSize, - ReceiveBufferSize = proxyServer.BufferSize, - LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds) - }; - - //linux has a bug with socket reuse in .net core. - if (proxyServer.ReuseSocket && RunTime.IsWindows || RunTime.IsRunningOnMono) - { - tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - - // If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections - if (useUpstreamProxy) - { - await tcpClient.ConnectAsync(externalProxy.HostName, externalProxy.Port); - } - else - { - await tcpClient.ConnectAsync(remoteHostName, remotePort); - } - - await proxyServer.InvokeConnectionCreateEvent(tcpClient, false); - - stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize); - - if (useUpstreamProxy && (isConnect || isHttps)) - { - var writer = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize); - var connectRequest = new ConnectRequest - { - OriginalUrl = $"{remoteHostName}:{remotePort}", - HttpVersion = httpVersion - }; - - connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive); - - if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null) - { - connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive); - connectRequest.Headers.AddHeader( - HttpHeader.GetProxyAuthorizationHeader(externalProxy.UserName, externalProxy.Password)); - } - - await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken); - - string httpStatus = await stream.ReadLineAsync(cancellationToken); - - Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription); - - if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") - && !statusDescription.EqualsIgnoreCase("Connection Established")) - { - throw new Exception("Upstream proxy failed to create a secure tunnel"); - } - - await stream.ReadAndIgnoreAllLinesAsync(cancellationToken); - } - - if (isHttps) - { - var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate, - proxyServer.SelectClientCertificate); - stream = new CustomBufferedStream(sslStream, proxyServer.BufferPool, proxyServer.BufferSize); - - var options = new SslClientAuthenticationOptions - { - ApplicationProtocols = applicationProtocols, - TargetHost = remoteHostName, - ClientCertificates = null, - EnabledSslProtocols = proxyServer.SupportedSslProtocols, - CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation - }; - await sslStream.AuthenticateAsClientAsync(options, cancellationToken); -#if NETCOREAPP2_1 - negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; -#endif - } - } - catch (Exception) - { - stream?.Dispose(); - tcpClient?.Close(); - throw; - } - - return new TcpServerConnection(proxyServer, tcpClient) - { - UpStreamProxy = externalProxy, - UpStreamEndPoint = upStreamEndPoint, - HostName = remoteHostName, - Port = remotePort, - IsHttps = isHttps, - NegotiatedApplicationProtocol = negotiatedApplicationProtocol, - UseUpstreamProxy = useUpstreamProxy, - StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize), - Stream = stream, - Version = httpVersion - }; - } - - - /// - /// Release connection back to cache. - /// - /// The Tcp server connection to return. - /// Should we just close the connection instead of reusing? - internal async Task Release(TcpServerConnection connection, bool close = false) - { - if (connection == null) - { - return; - } - - if (close || connection.IsWinAuthenticated || !server.EnableConnectionPool) - { - disposalBag.Add(connection); - return; - } - - connection.LastAccess = DateTime.Now; - - try - { - await @lock.WaitAsync(); - - while (true) - { - if (cache.TryGetValue(connection.CacheKey, out var existingConnections)) - { - while (existingConnections.Count >= server.MaxCachedConnections) - { - if (existingConnections.TryDequeue(out var staleConnection)) - { - disposalBag.Add(staleConnection); - } - } - - existingConnections.Enqueue(connection); - break; - } - - if (cache.TryAdd(connection.CacheKey, - new ConcurrentQueue(new[] { connection }))) - { - break; - } - } - - } - finally - { - @lock.Release(); - } - } - - internal async Task Release(Task connectionCreateTask, bool closeServerConnection) - { - if (connectionCreateTask != null) - { - TcpServerConnection connection = null; - try - { - connection = await connectionCreateTask; - } - catch { } - finally - { - await Release(connection, closeServerConnection); - } - } - } - - private async Task clearOutdatedConnections() - { - while (runCleanUpTask) - { - try - { - foreach (var item in cache) - { - var queue = item.Value; - - while (queue.Count > 0) - { - if (queue.TryDequeue(out var connection)) - { - var cutOff = DateTime.Now.AddSeconds(-1 * server.ConnectionTimeOutSeconds); - if (!server.EnableConnectionPool - || connection.LastAccess < cutOff) - { - disposalBag.Add(connection); - continue; - } - - queue.Enqueue(connection); - break; - } - } - } - - try - { - await @lock.WaitAsync(); - - //clear empty queues - var emptyKeys = cache.Where(x => x.Value.Count == 0).Select(x => x.Key).ToList(); - foreach (string key in emptyKeys) - { - cache.TryRemove(key, out var _); - } - } - finally - { - @lock.Release(); - } - - while (!disposalBag.IsEmpty) - { - if (disposalBag.TryTake(out var connection)) - { - connection?.Dispose(); - } - } - } - catch (Exception e) - { - server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e)); - } - finally - { - //cleanup every 3 seconds by default - await Task.Delay(1000 * 3); - } - - } - } - - public void Dispose() - { - runCleanUpTask = false; - - try - { - @lock.Wait(); - - foreach (var queue in cache.Select(x => x.Value).ToList()) - { - while (!queue.IsEmpty) - { - if (queue.TryDequeue(out var connection)) - { - disposalBag.Add(connection); - } - } - } - cache.Clear(); - } - finally - { - @lock.Release(); - } - - while (!disposalBag.IsEmpty) - { - if (disposalBag.TryTake(out var connection)) - { - connection?.Dispose(); - } - } - } - } -} - +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using StreamExtended.Network; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Helpers; +using Titanium.Web.Proxy.Http; +using Titanium.Web.Proxy.Models; + +namespace Titanium.Web.Proxy.Network.Tcp +{ + /// + /// A class that manages Tcp Connection to server used by this proxy server. + /// + internal class TcpConnectionFactory : IDisposable + { + //Tcp server connection pool cache + private readonly ConcurrentDictionary> cache + = new ConcurrentDictionary>(); + + //Tcp connections waiting to be disposed by cleanup task + private readonly ConcurrentBag disposalBag = + new ConcurrentBag(); + + //cache object race operations lock + private readonly SemaphoreSlim @lock = new SemaphoreSlim(1); + + private volatile bool runCleanUpTask = true; + + internal TcpConnectionFactory(ProxyServer server) + { + this.server = server; + Task.Run(async () => await clearOutdatedConnections()); + } + + internal ProxyServer server { get; set; } + + internal string GetConnectionCacheKey(string remoteHostName, int remotePort, + bool isHttps, List applicationProtocols, + ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy) + { + //http version is ignored since its an application level decision b/w HTTP 1.0/1.1 + //also when doing connect request MS Edge browser sends http 1.0 but uses 1.1 after server sends 1.1 its response. + //That can create cache miss for same server connection unneccessarily expecially when prefetcing with Connect. + //http version 2 is separated using applicationProtocols below. + var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" + + //when creating Tcp client isConnect won't matter + $"{isHttps}-"); + if (applicationProtocols != null) + { + foreach (var protocol in applicationProtocols.OrderBy(x => x)) + { + cacheKeyBuilder.Append($"{protocol}-"); + } + } + + cacheKeyBuilder.Append(upStreamEndPoint != null + ? $"{upStreamEndPoint.Address}-{upStreamEndPoint.Port}-" + : string.Empty); + cacheKeyBuilder.Append(externalProxy != null ? $"{externalProxy.GetCacheKey()}-" : string.Empty); + + return cacheKeyBuilder.ToString(); + + } + + /// + /// Gets the connection cache key. + /// + /// The session event arguments. + /// + /// + internal async Task GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args, + SslApplicationProtocol applicationProtocol) + { + List applicationProtocols = null; + if (applicationProtocol != default) + { + applicationProtocols = new List { applicationProtocol }; + } + + ExternalProxy customUpStreamProxy = null; + + bool isHttps = args.IsHttps; + if (server.GetCustomUpStreamProxyFunc != null) + { + customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); + } + + args.CustomUpStreamProxyUsed = customUpStreamProxy; + + return GetConnectionCacheKey( + args.WebSession.Request.RequestUri.Host, + args.WebSession.Request.RequestUri.Port, + isHttps, applicationProtocols, + server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, + customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy)); + } + + + /// + /// Create a server connection. + /// + /// The session event arguments. + /// Is this a CONNECT request. + /// + /// The cancellation token for this async task. + /// + internal Task GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, + SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken) + { + List applicationProtocols = null; + if (applicationProtocol != default) + { + applicationProtocols = new List { applicationProtocol }; + } + + return GetServerConnection(server, args, isConnect, applicationProtocols, noCache, cancellationToken); + } + + /// + /// Create a server connection. + /// + /// The session event arguments. + /// Is this a CONNECT request. + /// + /// The cancellation token for this async task. + /// + internal async Task GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, + List applicationProtocols, bool noCache, CancellationToken cancellationToken) + { + ExternalProxy customUpStreamProxy = null; + + bool isHttps = args.IsHttps; + if (server.GetCustomUpStreamProxyFunc != null) + { + customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); + } + + args.CustomUpStreamProxyUsed = customUpStreamProxy; + + return await GetServerConnection( + args.WebSession.Request.RequestUri.Host, + args.WebSession.Request.RequestUri.Port, + args.WebSession.Request.HttpVersion, + isHttps, applicationProtocols, isConnect, + server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, + customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy), + noCache, cancellationToken); + } + /// + /// Gets a TCP connection to server from connection pool. + /// + /// The remote hostname. + /// The remote port. + /// The http version to use. + /// Is this a HTTPS request. + /// The list of HTTPS application level protocol to negotiate if needed. + /// Is this a CONNECT request. + /// The current ProxyServer instance. + /// The local upstream endpoint to make request via. + /// The external proxy to make request via. + /// Not from cache/create new connection. + /// The cancellation token for this async task. + /// + internal async Task GetServerConnection(string remoteHostName, int remotePort, + Version httpVersion, bool isHttps, List applicationProtocols, bool isConnect, + ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, + bool noCache, CancellationToken cancellationToken) + { + var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort, + isHttps, applicationProtocols, + proxyServer, upStreamEndPoint, externalProxy); + + if (proxyServer.EnableConnectionPool && !noCache) + { + if (cache.TryGetValue(cacheKey, out var existingConnections)) + { + while (existingConnections.Count > 0) + { + if (existingConnections.TryDequeue(out var recentConnection)) + { + //+3 seconds for potential delay after getting connection + var cutOff = DateTime.Now.AddSeconds(-1 * proxyServer.ConnectionTimeOutSeconds + 3); + + if (recentConnection.LastAccess > cutOff + && recentConnection.TcpClient.IsGoodConnection()) + { + return recentConnection; + } + + disposalBag.Add(recentConnection); + } + } + } + } + + var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, + applicationProtocols, isConnect, proxyServer, upStreamEndPoint, externalProxy, cancellationToken); + + connection.CacheKey = cacheKey; + + return connection; + } + + /// + /// Creates a TCP connection to server + /// + /// The remote hostname. + /// The remote port. + /// The http version to use. + /// Is this a HTTPS request. + /// The list of HTTPS application level protocol to negotiate if needed. + /// Is this a CONNECT request. + /// The current ProxyServer instance. + /// The local upstream endpoint to make request via. + /// The external proxy to make request via. + /// The cancellation token for this async task. + /// + private async Task createServerConnection(string remoteHostName, int remotePort, + Version httpVersion, bool isHttps, List applicationProtocols, bool isConnect, + ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, + CancellationToken cancellationToken) + { + //deny connection to proxy end points to avoid infinite connection loop. + if (server.ProxyEndPoints.Any(x => x.Port == remotePort) + && NetworkHelper.IsLocalIpAddress(remoteHostName)) + { + throw new Exception($"A client is making HTTP request to one of the listening ports of this proxy {remoteHostName}:{remotePort}"); + } + + if (externalProxy != null) + { + if (server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port) + && NetworkHelper.IsLocalIpAddress(externalProxy.HostName)) + { + throw new Exception($"A client is making HTTP request via external proxy to one of the listening ports of this proxy {remoteHostName}:{remotePort}"); + } + } + + bool useUpstreamProxy = false; + + // check if external proxy is set for HTTP/HTTPS + if (externalProxy != null && + !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort)) + { + useUpstreamProxy = true; + + // check if we need to ByPass + if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName)) + { + useUpstreamProxy = false; + } + } + + TcpClient tcpClient = null; + CustomBufferedStream stream = null; + + SslApplicationProtocol negotiatedApplicationProtocol = default; + + try + { + tcpClient = new TcpClient(upStreamEndPoint) + { + ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, + SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, + SendBufferSize = proxyServer.BufferSize, + ReceiveBufferSize = proxyServer.BufferSize, + LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds) + }; + + //linux has a bug with socket reuse in .net core. + if (proxyServer.ReuseSocket && RunTime.IsWindows || RunTime.IsRunningOnMono) + { + tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + + // If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections + if (useUpstreamProxy) + { + await tcpClient.ConnectAsync(externalProxy.HostName, externalProxy.Port); + } + else + { + await tcpClient.ConnectAsync(remoteHostName, remotePort); + } + + await proxyServer.InvokeConnectionCreateEvent(tcpClient, false); + + stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize); + + if (useUpstreamProxy && (isConnect || isHttps)) + { + var writer = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize); + var connectRequest = new ConnectRequest + { + OriginalUrl = $"{remoteHostName}:{remotePort}", + HttpVersion = httpVersion + }; + + connectRequest.Headers.AddHeader(KnownHeaders.Connection, KnownHeaders.ConnectionKeepAlive); + + if (!string.IsNullOrEmpty(externalProxy.UserName) && externalProxy.Password != null) + { + connectRequest.Headers.AddHeader(HttpHeader.ProxyConnectionKeepAlive); + connectRequest.Headers.AddHeader( + HttpHeader.GetProxyAuthorizationHeader(externalProxy.UserName, externalProxy.Password)); + } + + await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken); + + string httpStatus = await stream.ReadLineAsync(cancellationToken); + + Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription); + + if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") + && !statusDescription.EqualsIgnoreCase("Connection Established")) + { + throw new Exception("Upstream proxy failed to create a secure tunnel"); + } + + await stream.ReadAndIgnoreAllLinesAsync(cancellationToken); + } + + if (isHttps) + { + var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate, + proxyServer.SelectClientCertificate); + stream = new CustomBufferedStream(sslStream, proxyServer.BufferPool, proxyServer.BufferSize); + + var options = new SslClientAuthenticationOptions + { + ApplicationProtocols = applicationProtocols, + TargetHost = remoteHostName, + ClientCertificates = null, + EnabledSslProtocols = proxyServer.SupportedSslProtocols, + CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation + }; + await sslStream.AuthenticateAsClientAsync(options, cancellationToken); +#if NETCOREAPP2_1 + negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; +#endif + } + } + catch (Exception) + { + stream?.Dispose(); + tcpClient?.Close(); + throw; + } + + return new TcpServerConnection(proxyServer, tcpClient) + { + UpStreamProxy = externalProxy, + UpStreamEndPoint = upStreamEndPoint, + HostName = remoteHostName, + Port = remotePort, + IsHttps = isHttps, + NegotiatedApplicationProtocol = negotiatedApplicationProtocol, + UseUpstreamProxy = useUpstreamProxy, + StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize), + Stream = stream, + Version = httpVersion + }; + } + + + /// + /// Release connection back to cache. + /// + /// The Tcp server connection to return. + /// Should we just close the connection instead of reusing? + internal async Task Release(TcpServerConnection connection, bool close = false) + { + if (connection == null) + { + return; + } + + if (close || connection.IsWinAuthenticated || !server.EnableConnectionPool) + { + disposalBag.Add(connection); + return; + } + + connection.LastAccess = DateTime.Now; + + try + { + await @lock.WaitAsync(); + + while (true) + { + if (cache.TryGetValue(connection.CacheKey, out var existingConnections)) + { + while (existingConnections.Count >= server.MaxCachedConnections) + { + if (existingConnections.TryDequeue(out var staleConnection)) + { + disposalBag.Add(staleConnection); + } + } + + existingConnections.Enqueue(connection); + break; + } + + if (cache.TryAdd(connection.CacheKey, + new ConcurrentQueue(new[] { connection }))) + { + break; + } + } + + } + finally + { + @lock.Release(); + } + } + + internal async Task Release(Task connectionCreateTask, bool closeServerConnection) + { + if (connectionCreateTask != null) + { + TcpServerConnection connection = null; + try + { + connection = await connectionCreateTask; + } + catch { } + finally + { + await Release(connection, closeServerConnection); + } + } + } + + private async Task clearOutdatedConnections() + { + while (runCleanUpTask) + { + try + { + foreach (var item in cache) + { + var queue = item.Value; + + while (queue.Count > 0) + { + if (queue.TryDequeue(out var connection)) + { + var cutOff = DateTime.Now.AddSeconds(-1 * server.ConnectionTimeOutSeconds); + if (!server.EnableConnectionPool + || connection.LastAccess < cutOff) + { + disposalBag.Add(connection); + continue; + } + + queue.Enqueue(connection); + break; + } + } + } + + try + { + await @lock.WaitAsync(); + + //clear empty queues + var emptyKeys = cache.Where(x => x.Value.Count == 0).Select(x => x.Key).ToList(); + foreach (string key in emptyKeys) + { + cache.TryRemove(key, out var _); + } + } + finally + { + @lock.Release(); + } + + while (!disposalBag.IsEmpty) + { + if (disposalBag.TryTake(out var connection)) + { + connection?.Dispose(); + } + } + } + catch (Exception e) + { + server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e)); + } + finally + { + //cleanup every 3 seconds by default + await Task.Delay(1000 * 3); + } + + } + } + + public void Dispose() + { + runCleanUpTask = false; + + try + { + @lock.Wait(); + + foreach (var queue in cache.Select(x => x.Value).ToList()) + { + while (!queue.IsEmpty) + { + if (queue.TryDequeue(out var connection)) + { + disposalBag.Add(connection); + } + } + } + cache.Clear(); + } + finally + { + @lock.Release(); + } + + while (!disposalBag.IsEmpty) + { + if (disposalBag.TryTake(out var connection)) + { + connection?.Dispose(); + } + } + } + } +} + diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs similarity index 100% rename from Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs rename to src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/Security/LittleEndian.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/Security/Message.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/Security/State.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/State.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/Security/State.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/Security/State.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/Security/WinAuthEndPoint.cs diff --git a/Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs b/src/Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs similarity index 100% rename from Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs rename to src/Titanium.Web.Proxy/Network/WinAuth/WinAuthHandler.cs diff --git a/Titanium.Web.Proxy/Properties/AssemblyInfo.cs b/src/Titanium.Web.Proxy/Properties/AssemblyInfo.cs similarity index 100% rename from Titanium.Web.Proxy/Properties/AssemblyInfo.cs rename to src/Titanium.Web.Proxy/Properties/AssemblyInfo.cs diff --git a/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs b/src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs similarity index 97% rename from Titanium.Web.Proxy/ProxyAuthorizationHandler.cs rename to src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs index bba6ece0d..ed26b65f5 100644 --- a/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs +++ b/src/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs @@ -1,159 +1,159 @@ -using System; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Exceptions; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Http; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Shared; - -namespace Titanium.Web.Proxy -{ - public partial class ProxyServer - { - /// - /// Callback to authorize clients of this proxy instance. - /// - /// The session event arguments. - /// True if authorized. - private async Task checkAuthorization(SessionEventArgsBase session) - { - // If we are not authorizing clients return true - if (ProxyBasicAuthenticateFunc == null && ProxySchemeAuthenticateFunc == null) - { - return true; - } - - var httpHeaders = session.WebSession.Request.Headers; - - try - { - var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization); - if (header == null) - { - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Required"); - return false; - } - - var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); - - if (headerValueParts.Length != 2) - { - // Return not authorized - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); - return false; - } - - if (ProxyBasicAuthenticateFunc != null) - { - return await authenticateUserBasic(session, headerValueParts); - } - - if (ProxySchemeAuthenticateFunc != null) - { - var result = await ProxySchemeAuthenticateFunc(session, headerValueParts[0], headerValueParts[1]); - - if (result.Result == ProxyAuthenticationResult.ContinuationNeeded) - { - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid", result.Continuation); - - return false; - } - - return result.Result == ProxyAuthenticationResult.Success; - } - - return false; - } - catch (Exception e) - { - ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, - httpHeaders)); - - // Return not authorized - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); - return false; - } - } - - private async Task authenticateUserBasic(SessionEventArgsBase session, string[] headerValueParts) - { - if (!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) - { - // Return not authorized - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); - return false; - } - - string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1])); - int colonIndex = decoded.IndexOf(':'); - if (colonIndex == -1) - { - // Return not authorized - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); - return false; - } - - string username = decoded.Substring(0, colonIndex); - string password = decoded.Substring(colonIndex + 1); - bool authenticated = await ProxyBasicAuthenticateFunc(session, username, password); - if (!authenticated) - { - session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); - } - - return authenticated; - } - - /// - /// Create an authentication required response. - /// - /// Response description. - /// - private Response createAuthentication407Response(string description, string continuation = null) - { - var response = new Response - { - HttpVersion = HttpHeader.Version11, - StatusCode = (int)HttpStatusCode.ProxyAuthenticationRequired, - StatusDescription = description - }; - - if (!string.IsNullOrWhiteSpace(continuation)) - { - return createContinuationResponse(response, continuation); - } - - if (ProxyBasicAuthenticateFunc != null) - { - response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, $"Basic realm=\"{ProxyAuthenticationRealm}\""); - } - - if (ProxySchemeAuthenticateFunc != null) - { - foreach (var scheme in ProxyAuthenticationSchemes) - { - response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, scheme); - } - } - - response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ProxyConnectionClose); - - response.Headers.FixProxyHeaders(); - return response; - } - - private Response createContinuationResponse(Response response, string continuation) - { - response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, continuation); - - response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ConnectionKeepAlive); - - response.Headers.FixProxyHeaders(); - - return response; - } - } -} +using System; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Exceptions; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Http; +using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Shared; + +namespace Titanium.Web.Proxy +{ + public partial class ProxyServer + { + /// + /// Callback to authorize clients of this proxy instance. + /// + /// The session event arguments. + /// True if authorized. + private async Task checkAuthorization(SessionEventArgsBase session) + { + // If we are not authorizing clients return true + if (ProxyBasicAuthenticateFunc == null && ProxySchemeAuthenticateFunc == null) + { + return true; + } + + var httpHeaders = session.WebSession.Request.Headers; + + try + { + var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization); + if (header == null) + { + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Required"); + return false; + } + + var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); + + if (headerValueParts.Length != 2) + { + // Return not authorized + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); + return false; + } + + if (ProxyBasicAuthenticateFunc != null) + { + return await authenticateUserBasic(session, headerValueParts); + } + + if (ProxySchemeAuthenticateFunc != null) + { + var result = await ProxySchemeAuthenticateFunc(session, headerValueParts[0], headerValueParts[1]); + + if (result.Result == ProxyAuthenticationResult.ContinuationNeeded) + { + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid", result.Continuation); + + return false; + } + + return result.Result == ProxyAuthenticationResult.Success; + } + + return false; + } + catch (Exception e) + { + ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, + httpHeaders)); + + // Return not authorized + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); + return false; + } + } + + private async Task authenticateUserBasic(SessionEventArgsBase session, string[] headerValueParts) + { + if (!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) + { + // Return not authorized + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); + return false; + } + + string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1])); + int colonIndex = decoded.IndexOf(':'); + if (colonIndex == -1) + { + // Return not authorized + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); + return false; + } + + string username = decoded.Substring(0, colonIndex); + string password = decoded.Substring(colonIndex + 1); + bool authenticated = await ProxyBasicAuthenticateFunc(session, username, password); + if (!authenticated) + { + session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); + } + + return authenticated; + } + + /// + /// Create an authentication required response. + /// + /// Response description. + /// + private Response createAuthentication407Response(string description, string continuation = null) + { + var response = new Response + { + HttpVersion = HttpHeader.Version11, + StatusCode = (int)HttpStatusCode.ProxyAuthenticationRequired, + StatusDescription = description + }; + + if (!string.IsNullOrWhiteSpace(continuation)) + { + return createContinuationResponse(response, continuation); + } + + if (ProxyBasicAuthenticateFunc != null) + { + response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, $"Basic realm=\"{ProxyAuthenticationRealm}\""); + } + + if (ProxySchemeAuthenticateFunc != null) + { + foreach (var scheme in ProxyAuthenticationSchemes) + { + response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, scheme); + } + } + + response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ProxyConnectionClose); + + response.Headers.FixProxyHeaders(); + return response; + } + + private Response createContinuationResponse(Response response, string continuation) + { + response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, continuation); + + response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ConnectionKeepAlive); + + response.Headers.FixProxyHeaders(); + + return response; + } + } +} diff --git a/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs similarity index 97% rename from Titanium.Web.Proxy/ProxyServer.cs rename to src/Titanium.Web.Proxy/ProxyServer.cs index aa8ea36fe..b83aeec47 100644 --- a/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -1,847 +1,847 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using StreamExtended; -using StreamExtended.Network; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Helpers; -using Titanium.Web.Proxy.Helpers.WinHttp; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network; -using Titanium.Web.Proxy.Network.Tcp; - -namespace Titanium.Web.Proxy -{ - /// - /// - /// This class is the backbone of proxy. One can create as many instances as needed. - /// However care should be taken to avoid using the same listening ports across multiple instances. - /// - public partial class ProxyServer : IDisposable - { - /// - /// HTTP & HTTPS scheme shorthands. - /// - internal static readonly string UriSchemeHttp = Uri.UriSchemeHttp; - internal static readonly string UriSchemeHttps = Uri.UriSchemeHttps; - - /// - /// A default exception log func. - /// - private readonly ExceptionHandler defaultExceptionFunc = e => { }; - - /// - /// Backing field for exposed public property. - /// - private int clientConnectionCount; - - /// - /// Backing field for exposed public property. - /// - private ExceptionHandler exceptionFunc; - - /// - /// Backing field for exposed public property. - /// - private int serverConnectionCount; - - /// - /// Upstream proxy manager. - /// - private WinHttpWebProxyFinder systemProxyResolver; - - /// - /// - /// Initializes a new instance of ProxyServer class with provided parameters. - /// - /// - /// Should fake HTTPS certificate be trusted by this machine's user certificate - /// store? - /// - /// Should fake HTTPS certificate be trusted by this machine's certificate store? - /// - /// Should we attempt to trust certificates with elevated permissions by - /// prompting for UAC if required? - /// - public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, - bool trustRootCertificateAsAdmin = false) : this(null, null, userTrustRootCertificate, - machineTrustRootCertificate, trustRootCertificateAsAdmin) - { - } - - /// - /// Initializes a new instance of ProxyServer class with provided parameters. - /// - /// Name of the root certificate. - /// Name of the root certificate issuer. - /// - /// Should fake HTTPS certificate be trusted by this machine's user certificate - /// store? - /// - /// Should fake HTTPS certificate be trusted by this machine's certificate store? - /// - /// Should we attempt to trust certificates with elevated permissions by - /// prompting for UAC if required? - /// - public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, - bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, - bool trustRootCertificateAsAdmin = false) - { - // default values - ConnectionTimeOutSeconds = 60; - - if (BufferPool == null) - { - BufferPool = new DefaultBufferPool(); - } - - ProxyEndPoints = new List(); - tcpConnectionFactory = new TcpConnectionFactory(this); - if (!RunTime.IsRunningOnMono && RunTime.IsWindows) - { - systemProxySettingsManager = new SystemProxyManager(); - } - - CertificateManager = new CertificateManager(rootCertificateName, rootCertificateIssuerName, - userTrustRootCertificate, machineTrustRootCertificate, trustRootCertificateAsAdmin, ExceptionFunc); - } - - /// - /// An factory that creates tcp connection to server. - /// - private TcpConnectionFactory tcpConnectionFactory { get; } - - /// - /// Manage system proxy settings. - /// - private SystemProxyManager systemProxySettingsManager { get; } - - //Number of exception retries when connection pool is enabled. - private int retries => EnableConnectionPool ? MaxCachedConnections : 0; - - /// - /// Is the proxy currently running? - /// - public bool ProxyRunning { get; private set; } - - /// - /// Gets or sets a value indicating whether requests will be chained to upstream gateway. - /// Defaults to false. - /// - public bool ForwardToUpstreamGateway { get; set; } - - /// - /// Enable disable Windows Authentication (NTLM/Kerberos). - /// Note: NTLM/Kerberos will always send local credentials of current user - /// running the proxy process. This is because a man - /// in middle attack with Windows domain authentication is not currently supported. - /// Defaults to false. - /// - public bool EnableWinAuth { get; set; } - - /// - /// Should we check for certificare revocation during SSL authentication to servers - /// Note: If enabled can reduce performance. Defaults to false. - /// - public X509RevocationMode CheckCertificateRevocation { get; set; } - - /// - /// Does this proxy uses the HTTP protocol 100 continue behaviour strictly? - /// Broken 100 contunue implementations on server/client may cause problems if enabled. - /// Defaults to false. - /// - public bool Enable100ContinueBehaviour { get; set; } - - /// - /// Should we enable experimental server connection pool? - /// Defaults to disable. - /// - public bool EnableConnectionPool { get; set; } - - /// - /// Buffer size in bytes used throughout this proxy. - /// Default value is 8192 bytes. - /// - public int BufferSize { get; set; } = 8192; - - /// - /// Seconds client/server connection are to be kept alive when waiting for read/write to complete. - /// This will also determine the pool eviction time when connection pool is enabled. - /// Default value is 60 seconds. - /// - public int ConnectionTimeOutSeconds { get; set; } - - /// - /// Maximum number of concurrent connections per remote host in cache. - /// Only valid when connection pooling is enabled. - /// Default value is 2. - /// - public int MaxCachedConnections { get; set; } = 2; - - /// - /// Number of seconds to linger when Tcp connection is in TIME_WAIT state. - /// Default value is 30. - /// - public int TcpTimeWaitSeconds { get; set; } = 30; - - /// - /// Should we reuse client/server tcp sockets. - /// Default is true (disabled for linux/macOS due to bug in .Net core). - /// - public bool ReuseSocket { get; set; } = true; - - /// - /// Total number of active client connections. - /// - public int ClientConnectionCount => clientConnectionCount; - - /// - /// Total number of active server connections. - /// - public int ServerConnectionCount => serverConnectionCount; - - /// - /// Realm used during Proxy Basic Authentication. - /// - public string ProxyAuthenticationRealm { get; set; } = "TitaniumProxy"; - - /// - /// List of supported Ssl versions. - /// - public SslProtocols SupportedSslProtocols { get; set; } = -#if NET45 - SslProtocols.Ssl3 | -#endif - SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; - - /// - /// The buffer pool used throughout this proxy instance. - /// Set custom implementations by implementing this interface. - /// By default this uses DefaultBufferPool implementation available in StreamExtended library package. - /// - public IBufferPool BufferPool { get; set; } - - /// - /// Manages certificates used by this proxy. - /// - public CertificateManager CertificateManager { get; } - - /// - /// External proxy used for Http requests. - /// - public ExternalProxy UpStreamHttpProxy { get; set; } - - /// - /// External proxy used for Https requests. - /// - public ExternalProxy UpStreamHttpsProxy { get; set; } - - /// - /// Local adapter/NIC endpoint where proxy makes request via. - /// Defaults via any IP addresses of this machine. - /// - public IPEndPoint UpStreamEndPoint { get; set; } = new IPEndPoint(IPAddress.Any, 0); - - /// - /// A list of IpAddress and port this proxy is listening to. - /// - public List ProxyEndPoints { get; set; } - - /// - /// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. - /// User should return the ExternalProxy object with valid credentials. - /// - public Func> GetCustomUpStreamProxyFunc { get; set; } - - /// - /// Callback for error events in this proxy instance. - /// - public ExceptionHandler ExceptionFunc - { - get => exceptionFunc ?? defaultExceptionFunc; - set - { - exceptionFunc = value; - CertificateManager.ExceptionFunc = value; - } - } - - /// - /// A callback to authenticate proxy clients via basic authentication. - /// Parameters are username and password as provided by client. - /// Should return true for successful authentication. - /// - public Func> ProxyBasicAuthenticateFunc { get; set; } - - /// - /// A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. - /// Parameters are current working session, schemeType, and token as provided by a calling client. - /// Should return success for successful authentication, continuation if the package requests, or failure. - /// - public Func> ProxySchemeAuthenticateFunc { get; set; } - - /// - /// A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. - /// Works in relation with ProxySchemeAuthenticateFunc. - /// - public IEnumerable ProxyAuthenticationSchemes { get; set; } = new string[0]; - - /// - /// Event occurs when client connection count changed. - /// - public event EventHandler ClientConnectionCountChanged; - - /// - /// Event occurs when server connection count changed. - /// - public event EventHandler ServerConnectionCountChanged; - - /// - /// Event to override the default verification logic of remote SSL certificate received during authentication. - /// - public event AsyncEventHandler ServerCertificateValidationCallback; - - /// - /// Event to override client certificate selection during mutual SSL authentication. - /// - public event AsyncEventHandler ClientCertificateSelectionCallback; - - /// - /// Intercept request event to server. - /// - public event AsyncEventHandler BeforeRequest; - - /// - /// Intercept response event from server. - /// - public event AsyncEventHandler BeforeResponse; - - /// - /// Intercept after response event from server. - /// - public event AsyncEventHandler AfterResponse; - - /// - /// Customize TcpClient used for client connection upon create. - /// - public event AsyncEventHandler OnClientConnectionCreate; - - /// - /// Customize TcpClient used for server connection upon create. - /// - public event AsyncEventHandler OnServerConnectionCreate; - - /// - /// Add a proxy end point. - /// - /// The proxy endpoint. - public void AddEndPoint(ProxyEndPoint endPoint) - { - if (ProxyEndPoints.Any(x => - x.IpAddress.Equals(endPoint.IpAddress) && endPoint.Port != 0 && x.Port == endPoint.Port)) - { - throw new Exception("Cannot add another endpoint to same port & ip address"); - } - - ProxyEndPoints.Add(endPoint); - - if (ProxyRunning) - { - listen(endPoint); - } - } - - /// - /// Remove a proxy end point. - /// Will throw error if the end point does'nt exist. - /// - /// The existing endpoint to remove. - public void RemoveEndPoint(ProxyEndPoint endPoint) - { - if (ProxyEndPoints.Contains(endPoint) == false) - { - throw new Exception("Cannot remove endPoints not added to proxy"); - } - - ProxyEndPoints.Remove(endPoint); - - if (ProxyRunning) - { - quitListen(endPoint); - } - } - - /// - /// Set the given explicit end point as the default proxy server for current machine. - /// - /// The explicit endpoint. - public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) - { - SetAsSystemProxy(endPoint, ProxyProtocolType.Http); - } - - /// - /// Set the given explicit end point as the default proxy server for current machine. - /// - /// The explicit endpoint. - public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) - { - SetAsSystemProxy(endPoint, ProxyProtocolType.Https); - } - - /// - /// Set the given explicit end point as the default proxy server for current machine. - /// - /// The explicit endpoint. - /// The proxy protocol type. - public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) - { - if (RunTime.IsRunningOnMono) - { - throw new Exception("Mono Runtime do not support system proxy settings."); - } - - validateEndPointAsSystemProxy(endPoint); - - bool isHttp = (protocolType & ProxyProtocolType.Http) > 0; - bool isHttps = (protocolType & ProxyProtocolType.Https) > 0; - - if (isHttps) - { - CertificateManager.EnsureRootCertificate(); - - // If certificate was trusted by the machine - if (!CertificateManager.CertValidated) - { - protocolType = protocolType & ~ProxyProtocolType.Https; - isHttps = false; - } - } - - // clear any settings previously added - if (isHttp) - { - ProxyEndPoints.OfType().ToList().ForEach(x => x.IsSystemHttpProxy = false); - } - - if (isHttps) - { - ProxyEndPoints.OfType().ToList().ForEach(x => x.IsSystemHttpsProxy = false); - } - - systemProxySettingsManager.SetProxy( - Equals(endPoint.IpAddress, IPAddress.Any) | - Equals(endPoint.IpAddress, IPAddress.Loopback) - ? "localhost" - : endPoint.IpAddress.ToString(), - endPoint.Port, - protocolType); - - if (isHttp) - { - endPoint.IsSystemHttpProxy = true; - } - - if (isHttps) - { - endPoint.IsSystemHttpsProxy = true; - } - - string proxyType = null; - switch (protocolType) - { - case ProxyProtocolType.Http: - proxyType = "HTTP"; - break; - case ProxyProtocolType.Https: - proxyType = "HTTPS"; - break; - case ProxyProtocolType.AllHttp: - proxyType = "HTTP and HTTPS"; - break; - } - - if (protocolType != ProxyProtocolType.None) - { - Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System {2} Proxy", endPoint.IpAddress, - endPoint.Port, proxyType); - } - } - - /// - /// Clear HTTP proxy settings of current machine. - /// - public void DisableSystemHttpProxy() - { - DisableSystemProxy(ProxyProtocolType.Http); - } - - /// - /// Clear HTTPS proxy settings of current machine. - /// - public void DisableSystemHttpsProxy() - { - DisableSystemProxy(ProxyProtocolType.Https); - } - - /// - /// Clear the specified proxy setting for current machine. - /// - public void DisableSystemProxy(ProxyProtocolType protocolType) - { - if (RunTime.IsRunningOnMono) - { - throw new Exception("Mono Runtime do not support system proxy settings."); - } - - systemProxySettingsManager.RemoveProxy(protocolType); - } - - /// - /// Clear all proxy settings for current machine. - /// - public void DisableAllSystemProxies() - { - if (RunTime.IsRunningOnMono) - { - throw new Exception("Mono Runtime do not support system proxy settings."); - } - - systemProxySettingsManager.DisableAllProxy(); - } - - /// - /// Start this proxy server instance. - /// - public void Start() - { - if (ProxyRunning) - { - throw new Exception("Proxy is already running."); - } - - if (ProxyEndPoints.OfType().Any(x => x.GenericCertificate == null)) - { - CertificateManager.EnsureRootCertificate(); - } - - // clear any system proxy settings which is pointing to our own endpoint (causing a cycle) - // due to ungracious proxy shutdown before or something else - if (systemProxySettingsManager != null && RunTime.IsWindows) - { - var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry(); - if (proxyInfo.Proxies != null) - { - var protocolToRemove = ProxyProtocolType.None; - foreach (var proxy in proxyInfo.Proxies.Values) - { - if (NetworkHelper.IsLocalIpAddress(proxy.HostName) - && ProxyEndPoints.Any(x => x.Port == proxy.Port)) - { - protocolToRemove |= proxy.ProtocolType; - } - } - - if (protocolToRemove != ProxyProtocolType.None) - { - systemProxySettingsManager.RemoveProxy(protocolToRemove, false); - } - } - } - - if (ForwardToUpstreamGateway && GetCustomUpStreamProxyFunc == null && systemProxySettingsManager != null) - { - // Use WinHttp to handle PAC/WAPD scripts. - systemProxyResolver = new WinHttpWebProxyFinder(); - systemProxyResolver.LoadFromIE(); - - GetCustomUpStreamProxyFunc = getSystemUpStreamProxy; - } - - ProxyRunning = true; - - CertificateManager.ClearIdleCertificates(); - - foreach (var endPoint in ProxyEndPoints) - { - listen(endPoint); - } - } - - /// - /// Stop this proxy server instance. - /// - public void Stop() - { - if (!ProxyRunning) - { - throw new Exception("Proxy is not running."); - } - - if (!RunTime.IsRunningOnMono && RunTime.IsWindows) - { - bool setAsSystemProxy = ProxyEndPoints.OfType() - .Any(x => x.IsSystemHttpProxy || x.IsSystemHttpsProxy); - - if (setAsSystemProxy) - { - systemProxySettingsManager.RestoreOriginalSettings(); - } - } - - foreach (var endPoint in ProxyEndPoints) - { - quitListen(endPoint); - } - - ProxyEndPoints.Clear(); - - CertificateManager?.StopClearIdleCertificates(); - tcpConnectionFactory.Dispose(); - - ProxyRunning = false; - } - - /// - /// Listen on given end point of local machine. - /// - /// The end point to listen. - private void listen(ProxyEndPoint endPoint) - { - endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port); - - //linux/macOS has a bug with socket reuse in .net core. - if (ReuseSocket && (RunTime.IsWindows || RunTime.IsRunningOnMono)) - { - endPoint.Listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - - try - { - endPoint.Listener.Start(); - - endPoint.Port = ((IPEndPoint)endPoint.Listener.LocalEndpoint).Port; - - // accept clients asynchronously - endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint); - } - catch (SocketException ex) - { - var pex = new Exception( - $"Endpoint {endPoint} failed to start. Check inner exception and exception data for details.", ex); - pex.Data.Add("ipAddress", endPoint.IpAddress); - pex.Data.Add("port", endPoint.Port); - throw pex; - } - } - - /// - /// Verify if its safe to set this end point as system proxy. - /// - /// The end point to validate. - private void validateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint) - { - if (endPoint == null) - { - throw new ArgumentNullException(nameof(endPoint)); - } - - if (ProxyEndPoints.Contains(endPoint) == false) - { - throw new Exception("Cannot set endPoints not added to proxy as system proxy"); - } - - if (!ProxyRunning) - { - throw new Exception("Cannot set system proxy settings before proxy has been started."); - } - } - - /// - /// Gets the system up stream proxy. - /// - /// The session. - /// The external proxy as task result. - private Task getSystemUpStreamProxy(SessionEventArgsBase sessionEventArgs) - { - var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri); - return Task.FromResult(proxy); - } - - /// - /// Act when a connection is received from client. - /// - private void onAcceptConnection(IAsyncResult asyn) - { - var endPoint = (ProxyEndPoint)asyn.AsyncState; - - TcpClient tcpClient = null; - - try - { - // based on end point type call appropriate request handlers - tcpClient = endPoint.Listener.EndAcceptTcpClient(asyn); - } - catch (ObjectDisposedException) - { - // The listener was Stop()'d, disposing the underlying socket and - // triggering the completion of the callback. We're already exiting, - // so just return. - return; - } - catch - { - // Other errors are discarded to keep proxy running - } - - if (tcpClient != null) - { - Task.Run(async () => { await handleClient(tcpClient, endPoint); }); - } - - // Get the listener that handles the client request. - endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint); - } - - /// - /// Handle the client. - /// - /// The client. - /// The proxy endpoint. - /// The task. - private async Task handleClient(TcpClient tcpClient, ProxyEndPoint endPoint) - { - tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; - tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000; - tcpClient.SendBufferSize = BufferSize; - tcpClient.ReceiveBufferSize = BufferSize; - tcpClient.LingerState = new LingerOption(true, TcpTimeWaitSeconds); - - await InvokeConnectionCreateEvent(tcpClient, true); - - using (var clientConnection = new TcpClientConnection(this, tcpClient)) - { - if (endPoint is TransparentProxyEndPoint tep) - { - await handleClient(tep, clientConnection); - } - else - { - await handleClient((ExplicitProxyEndPoint)endPoint, clientConnection); - } - } - } - - /// - /// Handle exception. - /// - /// The client stream. - /// The exception. - private void onException(CustomBufferedStream clientStream, Exception exception) - { -#if DEBUG - if (clientStream is DebugCustomBufferedStream debugStream) - { - debugStream.LogException(exception); - } -#endif - - ExceptionFunc(exception); - } - - /// - /// Quit listening on the given end point. - /// - private void quitListen(ProxyEndPoint endPoint) - { - endPoint.Listener.Stop(); - endPoint.Listener.Server.Dispose(); - } - - /// - /// Update client connection count. - /// - /// Should we increment/decrement? - internal void UpdateClientConnectionCount(bool increment) - { - if (increment) - { - Interlocked.Increment(ref clientConnectionCount); - } - else - { - Interlocked.Decrement(ref clientConnectionCount); - } - - ClientConnectionCountChanged?.Invoke(this, EventArgs.Empty); - } - - /// - /// Update server connection count. - /// - /// Should we increment/decrement? - internal void UpdateServerConnectionCount(bool increment) - { - if (increment) - { - Interlocked.Increment(ref serverConnectionCount); - } - else - { - Interlocked.Decrement(ref serverConnectionCount); - } - - ServerConnectionCountChanged?.Invoke(this, EventArgs.Empty); - } - - /// - /// Invoke client/server tcp connection events if subscribed by API user. - /// - /// The TcpClient object. - /// Is this a client connection created event? If not then we would assume that its a server connection create event. - /// - internal async Task InvokeConnectionCreateEvent(TcpClient client, bool isClientConnection) - { - //client connection created - if (isClientConnection && OnClientConnectionCreate != null) - { - await OnClientConnectionCreate.InvokeAsync(this, client, ExceptionFunc); - } - - //server connection created - if (!isClientConnection && OnServerConnectionCreate != null) - { - await OnServerConnectionCreate.InvokeAsync(this, client, ExceptionFunc); - } - } - - /// - /// Connection retry policy when using connection pool. - /// - private RetryPolicy retryPolicy() where T : Exception - { - return new RetryPolicy(retries, tcpConnectionFactory); - } - - /// - /// Dispose the Proxy instance. - /// - public void Dispose() - { - if (ProxyRunning) - { - Stop(); - } - - CertificateManager?.Dispose(); - BufferPool?.Dispose(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using StreamExtended; +using StreamExtended.Network; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Helpers; +using Titanium.Web.Proxy.Helpers.WinHttp; +using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network; +using Titanium.Web.Proxy.Network.Tcp; + +namespace Titanium.Web.Proxy +{ + /// + /// + /// This class is the backbone of proxy. One can create as many instances as needed. + /// However care should be taken to avoid using the same listening ports across multiple instances. + /// + public partial class ProxyServer : IDisposable + { + /// + /// HTTP & HTTPS scheme shorthands. + /// + internal static readonly string UriSchemeHttp = Uri.UriSchemeHttp; + internal static readonly string UriSchemeHttps = Uri.UriSchemeHttps; + + /// + /// A default exception log func. + /// + private readonly ExceptionHandler defaultExceptionFunc = e => { }; + + /// + /// Backing field for exposed public property. + /// + private int clientConnectionCount; + + /// + /// Backing field for exposed public property. + /// + private ExceptionHandler exceptionFunc; + + /// + /// Backing field for exposed public property. + /// + private int serverConnectionCount; + + /// + /// Upstream proxy manager. + /// + private WinHttpWebProxyFinder systemProxyResolver; + + /// + /// + /// Initializes a new instance of ProxyServer class with provided parameters. + /// + /// + /// Should fake HTTPS certificate be trusted by this machine's user certificate + /// store? + /// + /// Should fake HTTPS certificate be trusted by this machine's certificate store? + /// + /// Should we attempt to trust certificates with elevated permissions by + /// prompting for UAC if required? + /// + public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, + bool trustRootCertificateAsAdmin = false) : this(null, null, userTrustRootCertificate, + machineTrustRootCertificate, trustRootCertificateAsAdmin) + { + } + + /// + /// Initializes a new instance of ProxyServer class with provided parameters. + /// + /// Name of the root certificate. + /// Name of the root certificate issuer. + /// + /// Should fake HTTPS certificate be trusted by this machine's user certificate + /// store? + /// + /// Should fake HTTPS certificate be trusted by this machine's certificate store? + /// + /// Should we attempt to trust certificates with elevated permissions by + /// prompting for UAC if required? + /// + public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, + bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, + bool trustRootCertificateAsAdmin = false) + { + // default values + ConnectionTimeOutSeconds = 60; + + if (BufferPool == null) + { + BufferPool = new DefaultBufferPool(); + } + + ProxyEndPoints = new List(); + tcpConnectionFactory = new TcpConnectionFactory(this); + if (!RunTime.IsRunningOnMono && RunTime.IsWindows) + { + systemProxySettingsManager = new SystemProxyManager(); + } + + CertificateManager = new CertificateManager(rootCertificateName, rootCertificateIssuerName, + userTrustRootCertificate, machineTrustRootCertificate, trustRootCertificateAsAdmin, ExceptionFunc); + } + + /// + /// An factory that creates tcp connection to server. + /// + private TcpConnectionFactory tcpConnectionFactory { get; } + + /// + /// Manage system proxy settings. + /// + private SystemProxyManager systemProxySettingsManager { get; } + + //Number of exception retries when connection pool is enabled. + private int retries => EnableConnectionPool ? MaxCachedConnections : 0; + + /// + /// Is the proxy currently running? + /// + public bool ProxyRunning { get; private set; } + + /// + /// Gets or sets a value indicating whether requests will be chained to upstream gateway. + /// Defaults to false. + /// + public bool ForwardToUpstreamGateway { get; set; } + + /// + /// Enable disable Windows Authentication (NTLM/Kerberos). + /// Note: NTLM/Kerberos will always send local credentials of current user + /// running the proxy process. This is because a man + /// in middle attack with Windows domain authentication is not currently supported. + /// Defaults to false. + /// + public bool EnableWinAuth { get; set; } + + /// + /// Should we check for certificare revocation during SSL authentication to servers + /// Note: If enabled can reduce performance. Defaults to false. + /// + public X509RevocationMode CheckCertificateRevocation { get; set; } + + /// + /// Does this proxy uses the HTTP protocol 100 continue behaviour strictly? + /// Broken 100 contunue implementations on server/client may cause problems if enabled. + /// Defaults to false. + /// + public bool Enable100ContinueBehaviour { get; set; } + + /// + /// Should we enable experimental server connection pool? + /// Defaults to disable. + /// + public bool EnableConnectionPool { get; set; } + + /// + /// Buffer size in bytes used throughout this proxy. + /// Default value is 8192 bytes. + /// + public int BufferSize { get; set; } = 8192; + + /// + /// Seconds client/server connection are to be kept alive when waiting for read/write to complete. + /// This will also determine the pool eviction time when connection pool is enabled. + /// Default value is 60 seconds. + /// + public int ConnectionTimeOutSeconds { get; set; } + + /// + /// Maximum number of concurrent connections per remote host in cache. + /// Only valid when connection pooling is enabled. + /// Default value is 2. + /// + public int MaxCachedConnections { get; set; } = 2; + + /// + /// Number of seconds to linger when Tcp connection is in TIME_WAIT state. + /// Default value is 30. + /// + public int TcpTimeWaitSeconds { get; set; } = 30; + + /// + /// Should we reuse client/server tcp sockets. + /// Default is true (disabled for linux/macOS due to bug in .Net core). + /// + public bool ReuseSocket { get; set; } = true; + + /// + /// Total number of active client connections. + /// + public int ClientConnectionCount => clientConnectionCount; + + /// + /// Total number of active server connections. + /// + public int ServerConnectionCount => serverConnectionCount; + + /// + /// Realm used during Proxy Basic Authentication. + /// + public string ProxyAuthenticationRealm { get; set; } = "TitaniumProxy"; + + /// + /// List of supported Ssl versions. + /// + public SslProtocols SupportedSslProtocols { get; set; } = +#if NET45 + SslProtocols.Ssl3 | +#endif + SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; + + /// + /// The buffer pool used throughout this proxy instance. + /// Set custom implementations by implementing this interface. + /// By default this uses DefaultBufferPool implementation available in StreamExtended library package. + /// + public IBufferPool BufferPool { get; set; } + + /// + /// Manages certificates used by this proxy. + /// + public CertificateManager CertificateManager { get; } + + /// + /// External proxy used for Http requests. + /// + public ExternalProxy UpStreamHttpProxy { get; set; } + + /// + /// External proxy used for Https requests. + /// + public ExternalProxy UpStreamHttpsProxy { get; set; } + + /// + /// Local adapter/NIC endpoint where proxy makes request via. + /// Defaults via any IP addresses of this machine. + /// + public IPEndPoint UpStreamEndPoint { get; set; } = new IPEndPoint(IPAddress.Any, 0); + + /// + /// A list of IpAddress and port this proxy is listening to. + /// + public List ProxyEndPoints { get; set; } + + /// + /// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. + /// User should return the ExternalProxy object with valid credentials. + /// + public Func> GetCustomUpStreamProxyFunc { get; set; } + + /// + /// Callback for error events in this proxy instance. + /// + public ExceptionHandler ExceptionFunc + { + get => exceptionFunc ?? defaultExceptionFunc; + set + { + exceptionFunc = value; + CertificateManager.ExceptionFunc = value; + } + } + + /// + /// A callback to authenticate proxy clients via basic authentication. + /// Parameters are username and password as provided by client. + /// Should return true for successful authentication. + /// + public Func> ProxyBasicAuthenticateFunc { get; set; } + + /// + /// A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. + /// Parameters are current working session, schemeType, and token as provided by a calling client. + /// Should return success for successful authentication, continuation if the package requests, or failure. + /// + public Func> ProxySchemeAuthenticateFunc { get; set; } + + /// + /// A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. + /// Works in relation with ProxySchemeAuthenticateFunc. + /// + public IEnumerable ProxyAuthenticationSchemes { get; set; } = new string[0]; + + /// + /// Event occurs when client connection count changed. + /// + public event EventHandler ClientConnectionCountChanged; + + /// + /// Event occurs when server connection count changed. + /// + public event EventHandler ServerConnectionCountChanged; + + /// + /// Event to override the default verification logic of remote SSL certificate received during authentication. + /// + public event AsyncEventHandler ServerCertificateValidationCallback; + + /// + /// Event to override client certificate selection during mutual SSL authentication. + /// + public event AsyncEventHandler ClientCertificateSelectionCallback; + + /// + /// Intercept request event to server. + /// + public event AsyncEventHandler BeforeRequest; + + /// + /// Intercept response event from server. + /// + public event AsyncEventHandler BeforeResponse; + + /// + /// Intercept after response event from server. + /// + public event AsyncEventHandler AfterResponse; + + /// + /// Customize TcpClient used for client connection upon create. + /// + public event AsyncEventHandler OnClientConnectionCreate; + + /// + /// Customize TcpClient used for server connection upon create. + /// + public event AsyncEventHandler OnServerConnectionCreate; + + /// + /// Add a proxy end point. + /// + /// The proxy endpoint. + public void AddEndPoint(ProxyEndPoint endPoint) + { + if (ProxyEndPoints.Any(x => + x.IpAddress.Equals(endPoint.IpAddress) && endPoint.Port != 0 && x.Port == endPoint.Port)) + { + throw new Exception("Cannot add another endpoint to same port & ip address"); + } + + ProxyEndPoints.Add(endPoint); + + if (ProxyRunning) + { + listen(endPoint); + } + } + + /// + /// Remove a proxy end point. + /// Will throw error if the end point does'nt exist. + /// + /// The existing endpoint to remove. + public void RemoveEndPoint(ProxyEndPoint endPoint) + { + if (ProxyEndPoints.Contains(endPoint) == false) + { + throw new Exception("Cannot remove endPoints not added to proxy"); + } + + ProxyEndPoints.Remove(endPoint); + + if (ProxyRunning) + { + quitListen(endPoint); + } + } + + /// + /// Set the given explicit end point as the default proxy server for current machine. + /// + /// The explicit endpoint. + public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) + { + SetAsSystemProxy(endPoint, ProxyProtocolType.Http); + } + + /// + /// Set the given explicit end point as the default proxy server for current machine. + /// + /// The explicit endpoint. + public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) + { + SetAsSystemProxy(endPoint, ProxyProtocolType.Https); + } + + /// + /// Set the given explicit end point as the default proxy server for current machine. + /// + /// The explicit endpoint. + /// The proxy protocol type. + public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) + { + if (RunTime.IsRunningOnMono) + { + throw new Exception("Mono Runtime do not support system proxy settings."); + } + + validateEndPointAsSystemProxy(endPoint); + + bool isHttp = (protocolType & ProxyProtocolType.Http) > 0; + bool isHttps = (protocolType & ProxyProtocolType.Https) > 0; + + if (isHttps) + { + CertificateManager.EnsureRootCertificate(); + + // If certificate was trusted by the machine + if (!CertificateManager.CertValidated) + { + protocolType = protocolType & ~ProxyProtocolType.Https; + isHttps = false; + } + } + + // clear any settings previously added + if (isHttp) + { + ProxyEndPoints.OfType().ToList().ForEach(x => x.IsSystemHttpProxy = false); + } + + if (isHttps) + { + ProxyEndPoints.OfType().ToList().ForEach(x => x.IsSystemHttpsProxy = false); + } + + systemProxySettingsManager.SetProxy( + Equals(endPoint.IpAddress, IPAddress.Any) | + Equals(endPoint.IpAddress, IPAddress.Loopback) + ? "localhost" + : endPoint.IpAddress.ToString(), + endPoint.Port, + protocolType); + + if (isHttp) + { + endPoint.IsSystemHttpProxy = true; + } + + if (isHttps) + { + endPoint.IsSystemHttpsProxy = true; + } + + string proxyType = null; + switch (protocolType) + { + case ProxyProtocolType.Http: + proxyType = "HTTP"; + break; + case ProxyProtocolType.Https: + proxyType = "HTTPS"; + break; + case ProxyProtocolType.AllHttp: + proxyType = "HTTP and HTTPS"; + break; + } + + if (protocolType != ProxyProtocolType.None) + { + Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System {2} Proxy", endPoint.IpAddress, + endPoint.Port, proxyType); + } + } + + /// + /// Clear HTTP proxy settings of current machine. + /// + public void DisableSystemHttpProxy() + { + DisableSystemProxy(ProxyProtocolType.Http); + } + + /// + /// Clear HTTPS proxy settings of current machine. + /// + public void DisableSystemHttpsProxy() + { + DisableSystemProxy(ProxyProtocolType.Https); + } + + /// + /// Clear the specified proxy setting for current machine. + /// + public void DisableSystemProxy(ProxyProtocolType protocolType) + { + if (RunTime.IsRunningOnMono) + { + throw new Exception("Mono Runtime do not support system proxy settings."); + } + + systemProxySettingsManager.RemoveProxy(protocolType); + } + + /// + /// Clear all proxy settings for current machine. + /// + public void DisableAllSystemProxies() + { + if (RunTime.IsRunningOnMono) + { + throw new Exception("Mono Runtime do not support system proxy settings."); + } + + systemProxySettingsManager.DisableAllProxy(); + } + + /// + /// Start this proxy server instance. + /// + public void Start() + { + if (ProxyRunning) + { + throw new Exception("Proxy is already running."); + } + + if (ProxyEndPoints.OfType().Any(x => x.GenericCertificate == null)) + { + CertificateManager.EnsureRootCertificate(); + } + + // clear any system proxy settings which is pointing to our own endpoint (causing a cycle) + // due to ungracious proxy shutdown before or something else + if (systemProxySettingsManager != null && RunTime.IsWindows) + { + var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry(); + if (proxyInfo.Proxies != null) + { + var protocolToRemove = ProxyProtocolType.None; + foreach (var proxy in proxyInfo.Proxies.Values) + { + if (NetworkHelper.IsLocalIpAddress(proxy.HostName) + && ProxyEndPoints.Any(x => x.Port == proxy.Port)) + { + protocolToRemove |= proxy.ProtocolType; + } + } + + if (protocolToRemove != ProxyProtocolType.None) + { + systemProxySettingsManager.RemoveProxy(protocolToRemove, false); + } + } + } + + if (ForwardToUpstreamGateway && GetCustomUpStreamProxyFunc == null && systemProxySettingsManager != null) + { + // Use WinHttp to handle PAC/WAPD scripts. + systemProxyResolver = new WinHttpWebProxyFinder(); + systemProxyResolver.LoadFromIE(); + + GetCustomUpStreamProxyFunc = getSystemUpStreamProxy; + } + + ProxyRunning = true; + + CertificateManager.ClearIdleCertificates(); + + foreach (var endPoint in ProxyEndPoints) + { + listen(endPoint); + } + } + + /// + /// Stop this proxy server instance. + /// + public void Stop() + { + if (!ProxyRunning) + { + throw new Exception("Proxy is not running."); + } + + if (!RunTime.IsRunningOnMono && RunTime.IsWindows) + { + bool setAsSystemProxy = ProxyEndPoints.OfType() + .Any(x => x.IsSystemHttpProxy || x.IsSystemHttpsProxy); + + if (setAsSystemProxy) + { + systemProxySettingsManager.RestoreOriginalSettings(); + } + } + + foreach (var endPoint in ProxyEndPoints) + { + quitListen(endPoint); + } + + ProxyEndPoints.Clear(); + + CertificateManager?.StopClearIdleCertificates(); + tcpConnectionFactory.Dispose(); + + ProxyRunning = false; + } + + /// + /// Listen on given end point of local machine. + /// + /// The end point to listen. + private void listen(ProxyEndPoint endPoint) + { + endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port); + + //linux/macOS has a bug with socket reuse in .net core. + if (ReuseSocket && (RunTime.IsWindows || RunTime.IsRunningOnMono)) + { + endPoint.Listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + + try + { + endPoint.Listener.Start(); + + endPoint.Port = ((IPEndPoint)endPoint.Listener.LocalEndpoint).Port; + + // accept clients asynchronously + endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint); + } + catch (SocketException ex) + { + var pex = new Exception( + $"Endpoint {endPoint} failed to start. Check inner exception and exception data for details.", ex); + pex.Data.Add("ipAddress", endPoint.IpAddress); + pex.Data.Add("port", endPoint.Port); + throw pex; + } + } + + /// + /// Verify if its safe to set this end point as system proxy. + /// + /// The end point to validate. + private void validateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint) + { + if (endPoint == null) + { + throw new ArgumentNullException(nameof(endPoint)); + } + + if (ProxyEndPoints.Contains(endPoint) == false) + { + throw new Exception("Cannot set endPoints not added to proxy as system proxy"); + } + + if (!ProxyRunning) + { + throw new Exception("Cannot set system proxy settings before proxy has been started."); + } + } + + /// + /// Gets the system up stream proxy. + /// + /// The session. + /// The external proxy as task result. + private Task getSystemUpStreamProxy(SessionEventArgsBase sessionEventArgs) + { + var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri); + return Task.FromResult(proxy); + } + + /// + /// Act when a connection is received from client. + /// + private void onAcceptConnection(IAsyncResult asyn) + { + var endPoint = (ProxyEndPoint)asyn.AsyncState; + + TcpClient tcpClient = null; + + try + { + // based on end point type call appropriate request handlers + tcpClient = endPoint.Listener.EndAcceptTcpClient(asyn); + } + catch (ObjectDisposedException) + { + // The listener was Stop()'d, disposing the underlying socket and + // triggering the completion of the callback. We're already exiting, + // so just return. + return; + } + catch + { + // Other errors are discarded to keep proxy running + } + + if (tcpClient != null) + { + Task.Run(async () => { await handleClient(tcpClient, endPoint); }); + } + + // Get the listener that handles the client request. + endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint); + } + + /// + /// Handle the client. + /// + /// The client. + /// The proxy endpoint. + /// The task. + private async Task handleClient(TcpClient tcpClient, ProxyEndPoint endPoint) + { + tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; + tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000; + tcpClient.SendBufferSize = BufferSize; + tcpClient.ReceiveBufferSize = BufferSize; + tcpClient.LingerState = new LingerOption(true, TcpTimeWaitSeconds); + + await InvokeConnectionCreateEvent(tcpClient, true); + + using (var clientConnection = new TcpClientConnection(this, tcpClient)) + { + if (endPoint is TransparentProxyEndPoint tep) + { + await handleClient(tep, clientConnection); + } + else + { + await handleClient((ExplicitProxyEndPoint)endPoint, clientConnection); + } + } + } + + /// + /// Handle exception. + /// + /// The client stream. + /// The exception. + private void onException(CustomBufferedStream clientStream, Exception exception) + { +#if DEBUG + if (clientStream is DebugCustomBufferedStream debugStream) + { + debugStream.LogException(exception); + } +#endif + + ExceptionFunc(exception); + } + + /// + /// Quit listening on the given end point. + /// + private void quitListen(ProxyEndPoint endPoint) + { + endPoint.Listener.Stop(); + endPoint.Listener.Server.Dispose(); + } + + /// + /// Update client connection count. + /// + /// Should we increment/decrement? + internal void UpdateClientConnectionCount(bool increment) + { + if (increment) + { + Interlocked.Increment(ref clientConnectionCount); + } + else + { + Interlocked.Decrement(ref clientConnectionCount); + } + + ClientConnectionCountChanged?.Invoke(this, EventArgs.Empty); + } + + /// + /// Update server connection count. + /// + /// Should we increment/decrement? + internal void UpdateServerConnectionCount(bool increment) + { + if (increment) + { + Interlocked.Increment(ref serverConnectionCount); + } + else + { + Interlocked.Decrement(ref serverConnectionCount); + } + + ServerConnectionCountChanged?.Invoke(this, EventArgs.Empty); + } + + /// + /// Invoke client/server tcp connection events if subscribed by API user. + /// + /// The TcpClient object. + /// Is this a client connection created event? If not then we would assume that its a server connection create event. + /// + internal async Task InvokeConnectionCreateEvent(TcpClient client, bool isClientConnection) + { + //client connection created + if (isClientConnection && OnClientConnectionCreate != null) + { + await OnClientConnectionCreate.InvokeAsync(this, client, ExceptionFunc); + } + + //server connection created + if (!isClientConnection && OnServerConnectionCreate != null) + { + await OnServerConnectionCreate.InvokeAsync(this, client, ExceptionFunc); + } + } + + /// + /// Connection retry policy when using connection pool. + /// + private RetryPolicy retryPolicy() where T : Exception + { + return new RetryPolicy(retries, tcpConnectionFactory); + } + + /// + /// Dispose the Proxy instance. + /// + public void Dispose() + { + if (ProxyRunning) + { + Stop(); + } + + CertificateManager?.Dispose(); + BufferPool?.Dispose(); + } + } +} diff --git a/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs similarity index 97% rename from Titanium.Web.Proxy/RequestHandler.cs rename to src/Titanium.Web.Proxy/RequestHandler.cs index c73939635..f040ac93b 100644 --- a/Titanium.Web.Proxy/RequestHandler.cs +++ b/src/Titanium.Web.Proxy/RequestHandler.cs @@ -1,420 +1,420 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -#if NETCOREAPP2_1 -using System.Net.Security; -#endif -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using StreamExtended.Network; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Exceptions; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Helpers; -using Titanium.Web.Proxy.Http; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network.Tcp; -using Titanium.Web.Proxy.Shared; - -namespace Titanium.Web.Proxy -{ - /// - /// Handle the request - /// - public partial class ProxyServer - { - - private bool isWindowsAuthenticationEnabledAndSupported => - EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono; - - /// - /// This is the core request handler method for a particular connection from client. - /// Will create new session (request/response) sequence until - /// client/server abruptly terminates connection or by normal HTTP termination. - /// - /// The proxy endpoint. - /// The client connection. - /// The client stream. - /// The client stream writer. - /// The cancellation token source for this async task. - /// - /// The https hostname as appeared in CONNECT request if this is a HTTPS request from - /// explicit endpoint. - /// - /// The Connect request if this is a HTTPS request from explicit endpoint. - /// Prefetched server connection for current client using Connect/SNI headers. - private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection, - CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter, - CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest, - Task prefetchConnectionTask = null) - { - var prefetchTask = prefetchConnectionTask; - TcpServerConnection connection = null; - bool closeServerConnection = false; - - try - { - var cancellationToken = cancellationTokenSource.Token; - - // Loop through each subsequest request on this particular client connection - // (assuming HTTP connection is kept alive by client) - while (true) - { - // read the request line - string httpCmd = await clientStream.ReadLineAsync(cancellationToken); - - if (string.IsNullOrEmpty(httpCmd)) - { - return; - } - - var args = new SessionEventArgs(this, endPoint, cancellationTokenSource) - { - ProxyClient = { ClientConnection = clientConnection }, - WebSession = { ConnectRequest = connectRequest } - }; - - try - { - try - { - Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, - out var version); - - // Read the request headers in to unique and non-unique header collections - await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers, - cancellationToken); - - Uri httpRemoteUri; - if (ProxyConstants.UriSchemeRegex.IsMatch(httpUrl)) - { - try - { - httpRemoteUri = new Uri(httpUrl); - } - catch (Exception ex) - { - throw new Exception($"Invalid URI: '{httpUrl}'", ex); - } - } - else - { - string host = args.WebSession.Request.Host ?? httpsConnectHostname; - string hostAndPath = host; - if (httpUrl.StartsWith("/")) - { - hostAndPath += httpUrl; - } - - string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", - hostAndPath); - try - { - httpRemoteUri = new Uri(url); - } - catch (Exception ex) - { - throw new Exception($"Invalid URI: '{url}'", ex); - } - } - - var request = args.WebSession.Request; - request.RequestUri = httpRemoteUri; - request.OriginalUrl = httpUrl; - - request.Method = httpMethod; - request.HttpVersion = version; - args.ProxyClient.ClientStream = clientStream; - args.ProxyClient.ClientStreamWriter = clientStreamWriter; - - if (!args.IsTransparent) - { - // proxy authorization check - if (httpsConnectHostname == null && await checkAuthorization(args) == false) - { - await invokeBeforeResponse(args); - - // send the response - await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, - cancellationToken: cancellationToken); - return; - } - - prepareRequestHeaders(request.Headers); - request.Host = request.RequestUri.Authority; - } - - // if win auth is enabled - // we need a cache of request body - // so that we can send it after authentication in WinAuthHandler.cs - if (isWindowsAuthenticationEnabledAndSupported && request.HasBody) - { - await args.GetRequestBody(cancellationToken); - } - - //we need this to syphon out data from connection if API user changes them. - request.SetOriginalHeaders(); - - args.TimeLine["Request Received"] = DateTime.Now; - - // If user requested interception do it - await invokeBeforeRequest(args); - - var response = args.WebSession.Response; - - if (request.CancelRequest) - { - // syphon out the request body from client before setting the new body - await args.SyphonOutBodyAsync(true, cancellationToken); - - await handleHttpSessionResponse(args); - - if (!response.KeepAlive) - { - return; - } - - continue; - } - - //If prefetch task is available. - if (connection == null && prefetchTask != null) - { - connection = await prefetchTask; - prefetchTask = null; - } - - // create a new connection if cache key changes. - // only gets hit when connection pool is disabled. - // or when prefetch task has a unexpectedly different connection. - if (connection != null - && (await tcpConnectionFactory.GetConnectionCacheKey(this, args, - clientConnection.NegotiatedApplicationProtocol) - != connection.CacheKey)) - { - await tcpConnectionFactory.Release(connection); - connection = null; - } - - //a connection generator task with captured parameters via closure. - Func> generator = () => - tcpConnectionFactory.GetServerConnection(this, args, isConnect: false, - applicationProtocol:clientConnection.NegotiatedApplicationProtocol, - noCache: false, cancellationToken: cancellationToken); - - //for connection pool, retry fails until cache is exhausted. - var result = await retryPolicy().ExecuteAsync(async (serverConnection) => - { - args.TimeLine["Server Connection Created"] = DateTime.Now; - - // if upgrading to websocket then relay the request without reading the contents - if (request.UpgradeToWebSocket) - { - await handleWebSocketUpgrade(httpCmd, args, request, - response, clientStream, clientStreamWriter, - serverConnection, cancellationTokenSource, cancellationToken); - closeServerConnection = true; - return false; - } - - // construct the web request that we are going to issue on behalf of the client. - await handleHttpSessionRequest(serverConnection, args); - return true; - - }, generator, connection); - - //update connection to latest used - connection = result.LatestConnection; - - //throw if exception happened - if(!result.IsSuccess) - { - throw result.Exception; - } - - if(!result.Continue) - { - return; - } - - //user requested - if (args.WebSession.CloseServerConnection) - { - closeServerConnection = true; - return; - } - - // if connection is closing exit - if (!response.KeepAlive) - { - closeServerConnection = true; - return; - } - - if (cancellationTokenSource.IsCancellationRequested) - { - throw new Exception("Session was terminated by user."); - } - - //Get/release server connection for each HTTP session instead of per client connection. - //This will be more efficient especially when client is idly holding server connection - //between sessions without using it. - //Do not release authenticated connections for performance reasons. - //Otherwise it will keep authenticating per session. - if (EnableConnectionPool && connection!=null - && !connection.IsWinAuthenticated) - { - await tcpConnectionFactory.Release(connection); - connection = null; - } - - } - catch (Exception e) when (!(e is ProxyHttpException)) - { - throw new ProxyHttpException("Error occured whilst handling session request", e, args); - } - } - catch (Exception e) - { - args.Exception = e; - closeServerConnection = true; - throw; - } - finally - { - await invokeAfterResponse(args); - args.Dispose(); - } - } - } - finally - { - await tcpConnectionFactory.Release(connection, - closeServerConnection); - - await tcpConnectionFactory.Release(prefetchTask, closeServerConnection); - } - } - - /// - /// Handle a specific session (request/response sequence) - /// - /// The tcp connection. - /// The session event arguments. - /// - private async Task handleHttpSessionRequest(TcpServerConnection serverConnection, SessionEventArgs args) - { - var cancellationToken = args.CancellationTokenSource.Token; - var request = args.WebSession.Request; - request.Locked = true; - - var body = request.CompressBodyAndUpdateContentLength(); - - // if expect continue is enabled then send the headers first - // and see if server would return 100 conitinue - if (request.ExpectContinue) - { - args.WebSession.SetConnection(serverConnection); - await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, - cancellationToken); - } - - // If 100 continue was the response inform that to the client - if (Enable100ContinueBehaviour) - { - var clientStreamWriter = args.ProxyClient.ClientStreamWriter; - - if (request.Is100Continue) - { - await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, - (int)HttpStatusCode.Continue, "Continue", cancellationToken); - await clientStreamWriter.WriteLineAsync(cancellationToken); - } - else if (request.ExpectationFailed) - { - await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, - (int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken); - await clientStreamWriter.WriteLineAsync(cancellationToken); - } - } - - // If expect continue is not enabled then set the connectio and send request headers - if (!request.ExpectContinue) - { - args.WebSession.SetConnection(serverConnection); - await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, - cancellationToken); - } - - // check if content-length is > 0 - if (request.ContentLength > 0) - { - if (request.IsBodyRead) - { - var writer = args.WebSession.ServerConnection.StreamWriter; - await writer.WriteBodyAsync(body, request.IsChunked, cancellationToken); - } - else - { - if (!request.ExpectationFailed) - { - if (request.HasBody) - { - HttpWriter writer = args.WebSession.ServerConnection.StreamWriter; - await args.CopyRequestBodyAsync(writer, TransformationMode.None, cancellationToken); - } - } - } - } - - // If not expectation failed response was returned by server then parse response - if (!request.ExpectationFailed) - { - await handleHttpSessionResponse(args); - } - - args.TimeLine["Response Sent"] = DateTime.Now; - } - - /// - /// Prepare the request headers so that we can avoid encodings not parsable by this proxy - /// - private void prepareRequestHeaders(HeaderCollection requestHeaders) - { - string acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding); - - if (acceptEncoding != null) - { - var supportedAcceptEncoding = new List(); - - //only allow proxy supported compressions - supportedAcceptEncoding.AddRange(acceptEncoding.Split(',') - .Select(x => x.Trim()) - .Where(x => ProxyConstants.ProxySupportedCompressions.Contains(x))); - - //uncompressed is always supported by proxy - supportedAcceptEncoding.Add("identity"); - - requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, - string.Join(",", supportedAcceptEncoding)); - } - - requestHeaders.FixProxyHeaders(); - } - - /// - /// Invoke before request handler if it is set. - /// - /// The session event arguments. - /// - private async Task invokeBeforeRequest(SessionEventArgs args) - { - if (BeforeRequest != null) - { - await BeforeRequest.InvokeAsync(this, args, ExceptionFunc); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +#if NETCOREAPP2_1 +using System.Net.Security; +#endif +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using StreamExtended.Network; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Exceptions; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Helpers; +using Titanium.Web.Proxy.Http; +using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network.Tcp; +using Titanium.Web.Proxy.Shared; + +namespace Titanium.Web.Proxy +{ + /// + /// Handle the request + /// + public partial class ProxyServer + { + + private bool isWindowsAuthenticationEnabledAndSupported => + EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono; + + /// + /// This is the core request handler method for a particular connection from client. + /// Will create new session (request/response) sequence until + /// client/server abruptly terminates connection or by normal HTTP termination. + /// + /// The proxy endpoint. + /// The client connection. + /// The client stream. + /// The client stream writer. + /// The cancellation token source for this async task. + /// + /// The https hostname as appeared in CONNECT request if this is a HTTPS request from + /// explicit endpoint. + /// + /// The Connect request if this is a HTTPS request from explicit endpoint. + /// Prefetched server connection for current client using Connect/SNI headers. + private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection, + CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter, + CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest, + Task prefetchConnectionTask = null) + { + var prefetchTask = prefetchConnectionTask; + TcpServerConnection connection = null; + bool closeServerConnection = false; + + try + { + var cancellationToken = cancellationTokenSource.Token; + + // Loop through each subsequest request on this particular client connection + // (assuming HTTP connection is kept alive by client) + while (true) + { + // read the request line + string httpCmd = await clientStream.ReadLineAsync(cancellationToken); + + if (string.IsNullOrEmpty(httpCmd)) + { + return; + } + + var args = new SessionEventArgs(this, endPoint, cancellationTokenSource) + { + ProxyClient = { ClientConnection = clientConnection }, + WebSession = { ConnectRequest = connectRequest } + }; + + try + { + try + { + Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, + out var version); + + // Read the request headers in to unique and non-unique header collections + await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers, + cancellationToken); + + Uri httpRemoteUri; + if (ProxyConstants.UriSchemeRegex.IsMatch(httpUrl)) + { + try + { + httpRemoteUri = new Uri(httpUrl); + } + catch (Exception ex) + { + throw new Exception($"Invalid URI: '{httpUrl}'", ex); + } + } + else + { + string host = args.WebSession.Request.Host ?? httpsConnectHostname; + string hostAndPath = host; + if (httpUrl.StartsWith("/")) + { + hostAndPath += httpUrl; + } + + string url = string.Concat(httpsConnectHostname == null ? "http://" : "https://", + hostAndPath); + try + { + httpRemoteUri = new Uri(url); + } + catch (Exception ex) + { + throw new Exception($"Invalid URI: '{url}'", ex); + } + } + + var request = args.WebSession.Request; + request.RequestUri = httpRemoteUri; + request.OriginalUrl = httpUrl; + + request.Method = httpMethod; + request.HttpVersion = version; + args.ProxyClient.ClientStream = clientStream; + args.ProxyClient.ClientStreamWriter = clientStreamWriter; + + if (!args.IsTransparent) + { + // proxy authorization check + if (httpsConnectHostname == null && await checkAuthorization(args) == false) + { + await invokeBeforeResponse(args); + + // send the response + await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, + cancellationToken: cancellationToken); + return; + } + + prepareRequestHeaders(request.Headers); + request.Host = request.RequestUri.Authority; + } + + // if win auth is enabled + // we need a cache of request body + // so that we can send it after authentication in WinAuthHandler.cs + if (isWindowsAuthenticationEnabledAndSupported && request.HasBody) + { + await args.GetRequestBody(cancellationToken); + } + + //we need this to syphon out data from connection if API user changes them. + request.SetOriginalHeaders(); + + args.TimeLine["Request Received"] = DateTime.Now; + + // If user requested interception do it + await invokeBeforeRequest(args); + + var response = args.WebSession.Response; + + if (request.CancelRequest) + { + // syphon out the request body from client before setting the new body + await args.SyphonOutBodyAsync(true, cancellationToken); + + await handleHttpSessionResponse(args); + + if (!response.KeepAlive) + { + return; + } + + continue; + } + + //If prefetch task is available. + if (connection == null && prefetchTask != null) + { + connection = await prefetchTask; + prefetchTask = null; + } + + // create a new connection if cache key changes. + // only gets hit when connection pool is disabled. + // or when prefetch task has a unexpectedly different connection. + if (connection != null + && (await tcpConnectionFactory.GetConnectionCacheKey(this, args, + clientConnection.NegotiatedApplicationProtocol) + != connection.CacheKey)) + { + await tcpConnectionFactory.Release(connection); + connection = null; + } + + //a connection generator task with captured parameters via closure. + Func> generator = () => + tcpConnectionFactory.GetServerConnection(this, args, isConnect: false, + applicationProtocol:clientConnection.NegotiatedApplicationProtocol, + noCache: false, cancellationToken: cancellationToken); + + //for connection pool, retry fails until cache is exhausted. + var result = await retryPolicy().ExecuteAsync(async (serverConnection) => + { + args.TimeLine["Server Connection Created"] = DateTime.Now; + + // if upgrading to websocket then relay the request without reading the contents + if (request.UpgradeToWebSocket) + { + await handleWebSocketUpgrade(httpCmd, args, request, + response, clientStream, clientStreamWriter, + serverConnection, cancellationTokenSource, cancellationToken); + closeServerConnection = true; + return false; + } + + // construct the web request that we are going to issue on behalf of the client. + await handleHttpSessionRequest(serverConnection, args); + return true; + + }, generator, connection); + + //update connection to latest used + connection = result.LatestConnection; + + //throw if exception happened + if(!result.IsSuccess) + { + throw result.Exception; + } + + if(!result.Continue) + { + return; + } + + //user requested + if (args.WebSession.CloseServerConnection) + { + closeServerConnection = true; + return; + } + + // if connection is closing exit + if (!response.KeepAlive) + { + closeServerConnection = true; + return; + } + + if (cancellationTokenSource.IsCancellationRequested) + { + throw new Exception("Session was terminated by user."); + } + + //Get/release server connection for each HTTP session instead of per client connection. + //This will be more efficient especially when client is idly holding server connection + //between sessions without using it. + //Do not release authenticated connections for performance reasons. + //Otherwise it will keep authenticating per session. + if (EnableConnectionPool && connection!=null + && !connection.IsWinAuthenticated) + { + await tcpConnectionFactory.Release(connection); + connection = null; + } + + } + catch (Exception e) when (!(e is ProxyHttpException)) + { + throw new ProxyHttpException("Error occured whilst handling session request", e, args); + } + } + catch (Exception e) + { + args.Exception = e; + closeServerConnection = true; + throw; + } + finally + { + await invokeAfterResponse(args); + args.Dispose(); + } + } + } + finally + { + await tcpConnectionFactory.Release(connection, + closeServerConnection); + + await tcpConnectionFactory.Release(prefetchTask, closeServerConnection); + } + } + + /// + /// Handle a specific session (request/response sequence) + /// + /// The tcp connection. + /// The session event arguments. + /// + private async Task handleHttpSessionRequest(TcpServerConnection serverConnection, SessionEventArgs args) + { + var cancellationToken = args.CancellationTokenSource.Token; + var request = args.WebSession.Request; + request.Locked = true; + + var body = request.CompressBodyAndUpdateContentLength(); + + // if expect continue is enabled then send the headers first + // and see if server would return 100 conitinue + if (request.ExpectContinue) + { + args.WebSession.SetConnection(serverConnection); + await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, + cancellationToken); + } + + // If 100 continue was the response inform that to the client + if (Enable100ContinueBehaviour) + { + var clientStreamWriter = args.ProxyClient.ClientStreamWriter; + + if (request.Is100Continue) + { + await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, + (int)HttpStatusCode.Continue, "Continue", cancellationToken); + await clientStreamWriter.WriteLineAsync(cancellationToken); + } + else if (request.ExpectationFailed) + { + await clientStreamWriter.WriteResponseStatusAsync(args.WebSession.Response.HttpVersion, + (int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken); + await clientStreamWriter.WriteLineAsync(cancellationToken); + } + } + + // If expect continue is not enabled then set the connectio and send request headers + if (!request.ExpectContinue) + { + args.WebSession.SetConnection(serverConnection); + await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, + cancellationToken); + } + + // check if content-length is > 0 + if (request.ContentLength > 0) + { + if (request.IsBodyRead) + { + var writer = args.WebSession.ServerConnection.StreamWriter; + await writer.WriteBodyAsync(body, request.IsChunked, cancellationToken); + } + else + { + if (!request.ExpectationFailed) + { + if (request.HasBody) + { + HttpWriter writer = args.WebSession.ServerConnection.StreamWriter; + await args.CopyRequestBodyAsync(writer, TransformationMode.None, cancellationToken); + } + } + } + } + + // If not expectation failed response was returned by server then parse response + if (!request.ExpectationFailed) + { + await handleHttpSessionResponse(args); + } + + args.TimeLine["Response Sent"] = DateTime.Now; + } + + /// + /// Prepare the request headers so that we can avoid encodings not parsable by this proxy + /// + private void prepareRequestHeaders(HeaderCollection requestHeaders) + { + string acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding); + + if (acceptEncoding != null) + { + var supportedAcceptEncoding = new List(); + + //only allow proxy supported compressions + supportedAcceptEncoding.AddRange(acceptEncoding.Split(',') + .Select(x => x.Trim()) + .Where(x => ProxyConstants.ProxySupportedCompressions.Contains(x))); + + //uncompressed is always supported by proxy + supportedAcceptEncoding.Add("identity"); + + requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, + string.Join(",", supportedAcceptEncoding)); + } + + requestHeaders.FixProxyHeaders(); + } + + /// + /// Invoke before request handler if it is set. + /// + /// The session event arguments. + /// + private async Task invokeBeforeRequest(SessionEventArgs args) + { + if (BeforeRequest != null) + { + await BeforeRequest.InvokeAsync(this, args, ExceptionFunc); + } + } + } +} diff --git a/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs similarity index 97% rename from Titanium.Web.Proxy/ResponseHandler.cs rename to src/Titanium.Web.Proxy/ResponseHandler.cs index f0120012f..427ba68bc 100644 --- a/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -1,155 +1,155 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Network.WinAuth.Security; - -namespace Titanium.Web.Proxy -{ - /// - /// Handle the response from server. - /// - public partial class ProxyServer - { - /// - /// Called asynchronously when a request was successfull and we received the response. - /// - /// The session event arguments. - /// The task. - private async Task handleHttpSessionResponse(SessionEventArgs args) - { - var cancellationToken = args.CancellationTokenSource.Token; - - // read response & headers from server - await args.WebSession.ReceiveResponse(cancellationToken); - - args.TimeLine["Response Received"] = DateTime.Now; - - var response = args.WebSession.Response; - args.ReRequest = false; - - // check for windows authentication - if (isWindowsAuthenticationEnabledAndSupported) - { - if (response.StatusCode == (int)HttpStatusCode.Unauthorized) - { - await handle401UnAuthorized(args); - } - else - { - WinAuthEndPoint.AuthenticatedResponse(args.WebSession.Data); - } - } - - //save original values so that if user changes them - //we can still use original values when syphoning out data from attached tcp connection. - response.SetOriginalHeaders(); - - // if user requested call back then do it - if (!response.Locked) - { - await invokeBeforeResponse(args); - } - - // it may changed in the user event - response = args.WebSession.Response; - - var clientStreamWriter = args.ProxyClient.ClientStreamWriter; - - //user set custom response by ignoring original response from server. - if (response.Locked) - { - //write custom user response with body and return. - await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); - - if(args.WebSession.ServerConnection != null - && !args.WebSession.CloseServerConnection) - { - // syphon out the original response body from server connection - // so that connection will be good to be reused. - await args.SyphonOutBodyAsync(false, cancellationToken); - } - - return; - } - - // if user requested to send request again - // likely after making modifications from User Response Handler - if (args.ReRequest) - { - // clear current response - await args.ClearResponse(cancellationToken); - await handleHttpSessionRequest(args.WebSession.ServerConnection, args); - return; - } - - response.Locked = true; - - // Write back to client 100-conitinue response if that's what server returned - if (response.Is100Continue) - { - await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, - (int)HttpStatusCode.Continue, "Continue", cancellationToken); - await clientStreamWriter.WriteLineAsync(cancellationToken); - } - else if (response.ExpectationFailed) - { - await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, - (int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken); - await clientStreamWriter.WriteLineAsync(cancellationToken); - } - - if (!args.IsTransparent) - { - response.Headers.FixProxyHeaders(); - } - - if (response.IsBodyRead) - { - await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); - } - else - { - // Write back response status to client - await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, - response.StatusDescription, cancellationToken); - await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken); - - // Write body if exists - if (response.HasBody) - { - await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None, - cancellationToken); - } - } - - } - - /// - /// Invoke before response if it is set. - /// - /// - /// - private async Task invokeBeforeResponse(SessionEventArgs args) - { - if (BeforeResponse != null) - { - await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); - } - } - - /// - /// Invoke after response if it is set. - /// - /// - /// - private async Task invokeAfterResponse(SessionEventArgs args) - { - if (AfterResponse != null) - { - await AfterResponse.InvokeAsync(this, args, ExceptionFunc); - } - } - } -} +using System; +using System.Net; +using System.Threading.Tasks; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Network.WinAuth.Security; + +namespace Titanium.Web.Proxy +{ + /// + /// Handle the response from server. + /// + public partial class ProxyServer + { + /// + /// Called asynchronously when a request was successfull and we received the response. + /// + /// The session event arguments. + /// The task. + private async Task handleHttpSessionResponse(SessionEventArgs args) + { + var cancellationToken = args.CancellationTokenSource.Token; + + // read response & headers from server + await args.WebSession.ReceiveResponse(cancellationToken); + + args.TimeLine["Response Received"] = DateTime.Now; + + var response = args.WebSession.Response; + args.ReRequest = false; + + // check for windows authentication + if (isWindowsAuthenticationEnabledAndSupported) + { + if (response.StatusCode == (int)HttpStatusCode.Unauthorized) + { + await handle401UnAuthorized(args); + } + else + { + WinAuthEndPoint.AuthenticatedResponse(args.WebSession.Data); + } + } + + //save original values so that if user changes them + //we can still use original values when syphoning out data from attached tcp connection. + response.SetOriginalHeaders(); + + // if user requested call back then do it + if (!response.Locked) + { + await invokeBeforeResponse(args); + } + + // it may changed in the user event + response = args.WebSession.Response; + + var clientStreamWriter = args.ProxyClient.ClientStreamWriter; + + //user set custom response by ignoring original response from server. + if (response.Locked) + { + //write custom user response with body and return. + await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); + + if(args.WebSession.ServerConnection != null + && !args.WebSession.CloseServerConnection) + { + // syphon out the original response body from server connection + // so that connection will be good to be reused. + await args.SyphonOutBodyAsync(false, cancellationToken); + } + + return; + } + + // if user requested to send request again + // likely after making modifications from User Response Handler + if (args.ReRequest) + { + // clear current response + await args.ClearResponse(cancellationToken); + await handleHttpSessionRequest(args.WebSession.ServerConnection, args); + return; + } + + response.Locked = true; + + // Write back to client 100-conitinue response if that's what server returned + if (response.Is100Continue) + { + await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, + (int)HttpStatusCode.Continue, "Continue", cancellationToken); + await clientStreamWriter.WriteLineAsync(cancellationToken); + } + else if (response.ExpectationFailed) + { + await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, + (int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken); + await clientStreamWriter.WriteLineAsync(cancellationToken); + } + + if (!args.IsTransparent) + { + response.Headers.FixProxyHeaders(); + } + + if (response.IsBodyRead) + { + await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); + } + else + { + // Write back response status to client + await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, + response.StatusDescription, cancellationToken); + await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken); + + // Write body if exists + if (response.HasBody) + { + await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None, + cancellationToken); + } + } + + } + + /// + /// Invoke before response if it is set. + /// + /// + /// + private async Task invokeBeforeResponse(SessionEventArgs args) + { + if (BeforeResponse != null) + { + await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); + } + } + + /// + /// Invoke after response if it is set. + /// + /// + /// + private async Task invokeAfterResponse(SessionEventArgs args) + { + if (AfterResponse != null) + { + await AfterResponse.InvokeAsync(this, args, ExceptionFunc); + } + } + } +} diff --git a/Titanium.Web.Proxy/Settings.StyleCop b/src/Titanium.Web.Proxy/Settings.StyleCop similarity index 100% rename from Titanium.Web.Proxy/Settings.StyleCop rename to src/Titanium.Web.Proxy/Settings.StyleCop diff --git a/Titanium.Web.Proxy/Shared/ProxyConstants.cs b/src/Titanium.Web.Proxy/Shared/ProxyConstants.cs similarity index 100% rename from Titanium.Web.Proxy/Shared/ProxyConstants.cs rename to src/Titanium.Web.Proxy/Shared/ProxyConstants.cs diff --git a/Tests/Titanium.Web.Proxy.UnitTests/StrongNameKey.snk b/src/Titanium.Web.Proxy/StrongNameKey.snk similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/StrongNameKey.snk rename to src/Titanium.Web.Proxy/StrongNameKey.snk diff --git a/Titanium.Web.Proxy/Titanium.Web.Proxy.Docs.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Docs.csproj similarity index 100% rename from Titanium.Web.Proxy/Titanium.Web.Proxy.Docs.csproj rename to src/Titanium.Web.Proxy/Titanium.Web.Proxy.Docs.csproj diff --git a/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj similarity index 97% rename from Titanium.Web.Proxy/Titanium.Web.Proxy.csproj rename to src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj index 6812a630a..1ec2f81de 100644 --- a/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj @@ -1,64 +1,64 @@ - - - - net45;netstandard2.0 - Titanium.Web.Proxy - false - True - StrongNameKey.snk - False - True - 7.1 - - - - - - - - - - 4.4.0 - - - 4.4.1 - - - - - - 4.4.0 - - - 4.4.1 - - - - - - - - - - True - True - - - True - True - - - True - True - - - True - True - - - True - True - - - + + + + net45;netstandard2.0 + Titanium.Web.Proxy + false + True + StrongNameKey.snk + False + True + 7.1 + + + + + + + + + + 4.4.0 + + + 4.4.1 + + + + + + 4.4.0 + + + 4.4.1 + + + + + + + + + + True + True + + + True + True + + + True + True + + + True + True + + + True + True + + + \ No newline at end of file diff --git a/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec similarity index 100% rename from Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec rename to src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec diff --git a/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs similarity index 100% rename from Titanium.Web.Proxy/TransparentClientHandler.cs rename to src/Titanium.Web.Proxy/TransparentClientHandler.cs diff --git a/Titanium.Web.Proxy/WebSocketHandler.cs b/src/Titanium.Web.Proxy/WebSocketHandler.cs similarity index 100% rename from Titanium.Web.Proxy/WebSocketHandler.cs rename to src/Titanium.Web.Proxy/WebSocketHandler.cs diff --git a/Titanium.Web.Proxy/WinAuthHandler.cs b/src/Titanium.Web.Proxy/WinAuthHandler.cs similarity index 100% rename from Titanium.Web.Proxy/WinAuthHandler.cs rename to src/Titanium.Web.Proxy/WinAuthHandler.cs diff --git a/Titanium.Web.Proxy/app.config b/src/Titanium.Web.Proxy/app.config similarity index 100% rename from Titanium.Web.Proxy/app.config rename to src/Titanium.Web.Proxy/app.config diff --git a/Titanium.Web.Proxy/packages.config b/src/Titanium.Web.Proxy/packages.config similarity index 100% rename from Titanium.Web.Proxy/packages.config rename to src/Titanium.Web.Proxy/packages.config diff --git a/Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs rename to tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs diff --git a/Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs rename to tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs diff --git a/Tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj similarity index 96% rename from Tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj rename to tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 54e2370da..83419f237 100644 --- a/Tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -56,8 +56,8 @@ - - {8d73a1be-868c-42d2-9ece-f32cc1a02906} + + {91018b6d-a7a9-45be-9cb3-79cbb8b169a6} Titanium.Web.Proxy diff --git a/Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs b/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs rename to tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs diff --git a/Tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs rename to tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs diff --git a/Tests/Titanium.Web.Proxy.UnitTests/ProxyServerTests.cs b/tests/Titanium.Web.Proxy.UnitTests/ProxyServerTests.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/ProxyServerTests.cs rename to tests/Titanium.Web.Proxy.UnitTests/ProxyServerTests.cs diff --git a/Titanium.Web.Proxy/StrongNameKey.snk b/tests/Titanium.Web.Proxy.UnitTests/StrongNameKey.snk similarity index 100% rename from Titanium.Web.Proxy/StrongNameKey.snk rename to tests/Titanium.Web.Proxy.UnitTests/StrongNameKey.snk diff --git a/Tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs b/tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs rename to tests/Titanium.Web.Proxy.UnitTests/SystemProxyTest.cs diff --git a/Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj similarity index 96% rename from Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj rename to tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj index 66842a31b..45d09949d 100644 --- a/Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj +++ b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj @@ -65,13 +65,13 @@ - - {8d73a1be-868c-42d2-9ece-f32cc1a02906} - Titanium.Web.Proxy - + - + + {91018b6d-a7a9-45be-9cb3-79cbb8b169a6} + Titanium.Web.Proxy + diff --git a/Tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs b/tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs similarity index 100% rename from Tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs rename to tests/Titanium.Web.Proxy.UnitTests/WinAuthTests.cs From 879445bf7869548b505369df27cdf3b85265fe95 Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Thu, 30 Aug 2018 14:11:21 -0400 Subject: [PATCH 02/40] set repo root --- .build/build.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.build/build.ps1 b/.build/build.ps1 index 1e79ce7f0..9ba2fa1d1 100644 --- a/.build/build.ps1 +++ b/.build/build.ps1 @@ -2,7 +2,8 @@ $PSake.use_exit_on_error = $true $Here = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" -$SolutionRoot = "$(Split-Path -parent $Here)\src" +$RepoRoot = $(Split-Path -parent $Here) +$SolutionRoot = "$RepoRoot\src" $ProjectName = "Titanium.Web.Proxy" $GitHubProjectName = "Titanium-Web-Proxy" @@ -65,12 +66,13 @@ Task Document -depends Build { if($Branch -eq "master") { + #use docfx to generate API documentation from source metadata docfx docfx.json #patch index.json so that it is always sorted #otherwise git will think file was changed - $IndexJsonFile = "$SolutionRoot\docs\index.json" + $IndexJsonFile = "$RepoRoot\docs\index.json" $unsorted = Get-Content $IndexJsonFile | Out-String [Reflection.Assembly]::LoadFile("$Here\lib\Newtonsoft.Json.dll") [System.Reflection.Assembly]::LoadWithPartialName("System") @@ -79,7 +81,7 @@ Task Document -depends Build { Set-Content -Path $IndexJsonFile -Value $obj #setup clone directory - $TEMP_REPO_DIR =(Split-Path -parent $SolutionRoot) + "\temp-repo-clone" + $TEMP_REPO_DIR =(Split-Path -parent $RepoRoot) + "\temp-repo-clone" If(test-path $TEMP_REPO_DIR) { @@ -101,7 +103,7 @@ Task Document -depends Build { cd "$TEMP_REPO_DIR\docs" #copy docs to clone directory\docs - Copy-Item -Path "$SolutionRoot\docs\*" -Destination "$TEMP_REPO_DIR\docs" -Recurse -Force + Copy-Item -Path "$RepoRoot\docs\*" -Destination "$TEMP_REPO_DIR\docs" -Recurse -Force #push changes to master git config --global credential.helper store From 00c3fc6f415ba63b78f932d414f166a0323022dc Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Thu, 30 Aug 2018 14:28:04 -0400 Subject: [PATCH 03/40] nuget fix --- .build/build.ps1 | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.build/build.ps1 b/.build/build.ps1 index 9ba2fa1d1..e688cb481 100644 --- a/.build/build.ps1 +++ b/.build/build.ps1 @@ -27,7 +27,7 @@ if(!$Branch) { $Branch = "local" } if($Branch -eq "beta" ) { $Version = "$Version-beta" } -$NuGet = Join-Path $SolutionRoot ".nuget\nuget.exe" +$NuGet = Join-Path $RepoRoot ".nuget\nuget.exe" $MSBuild = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe" $MSBuild -replace ' ', '` ' @@ -121,5 +121,5 @@ Task Document -depends Build { #package nuget files Task Package -depends Document { - exec { . $NuGet pack "$SolutionRoot\$ProjectName\$ProjectName.nuspec" -Properties Configuration=$Configuration -OutputDirectory "$SolutionRoot" -Version "$Version" } + exec { . $NuGet pack "$SolutionRoot\$ProjectName\$ProjectName.nuspec" -Properties Configuration=$Configuration -OutputDirectory "$RepoRoot" -Version "$Version" } } diff --git a/README.md b/README.md index 0cebe4997..daf39757b 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ Kindly report only issues/bugs here . For programming help or questions use [Sta **Console example application screenshot** -![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/Examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG) +![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG) **GUI example application screenshot** -![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/Examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG) +![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG) ### Features From 2c0e49b20a9284edacf613865bf26d3d0268307b Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Thu, 30 Aug 2018 15:52:08 -0400 Subject: [PATCH 04/40] docs fix --- _config.yml | 2 +- src/Titanium.Web.Proxy.Docs.sln | 6 +++--- src/Titanium.Web.Proxy.sln | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/_config.yml b/_config.yml index 7ceb9188b..e8034a2e9 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1 @@ -baseurl: /src +baseurl: /Titanium-Web-Proxy diff --git a/src/Titanium.Web.Proxy.Docs.sln b/src/Titanium.Web.Proxy.Docs.sln index 93bf07934..e2a2a410d 100644 --- a/src/Titanium.Web.Proxy.Docs.sln +++ b/src/Titanium.Web.Proxy.Docs.sln @@ -5,9 +5,9 @@ VisualStudioVersion = 15.0.27428.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B84B-9283-4E9C-8C43-A234E9AA3EAA}" ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets + ..\.nuget\NuGet.Config = ..\.nuget\NuGet.Config + ..\.nuget\NuGet.exe = ..\.nuget\NuGet.exe + ..\.nuget\NuGet.targets = ..\.nuget\NuGet.targets EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Docs", "Titanium.Web.Proxy\Titanium.Web.Proxy.Docs.csproj", "{EBF2EA46-EA00-4350-BE1D-D86AFD699DB3}" diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln index e431cf2a3..25df39a28 100644 --- a/src/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -7,22 +7,23 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{B6 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B84B-9283-4E9C-8C43-A234E9AA3EAA}" ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets + ..\.nuget\NuGet.Config = ..\.nuget\NuGet.Config + ..\.nuget\NuGet.exe = ..\.nuget\NuGet.exe + ..\.nuget\NuGet.targets = ..\.nuget\NuGet.targets EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{38EA62D0-D2CB-465D-AF4F-407C5B4D4A1E}" ProjectSection(SolutionItems) = preProject - LICENSE = LICENSE - README.md = README.md + ..\LICENSE = ..\LICENSE + ..\PULL_REQUEST_TEMPLATE.md = ..\PULL_REQUEST_TEMPLATE.md + ..\README.md = ..\README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AC9AE37A-3059-4FDB-9A5C-363AD86F2EEF}" ProjectSection(SolutionItems) = preProject - .build\Bootstrap.ps1 = .build\Bootstrap.ps1 - .build\Common.psm1 = .build\Common.psm1 - .build\default.ps1 = .build\default.ps1 + ..\.build\build.ps1 = ..\.build\build.ps1 + ..\.build\docfx.json = ..\.build\docfx.json + ..\.build\setup.ps1 = ..\.build\setup.ps1 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC1E0789-D348-49CF-8B67-5E99D50EDF64}" @@ -74,7 +75,7 @@ Global {4406CE17-9A39-4F28-8363-6169A4F799C1} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A} + EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 EndGlobalSection EndGlobal From 6ae4989e407c4d45fa060f4edeaa05dc0a31fbbc Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 1 Sep 2018 09:44:54 -0400 Subject: [PATCH 05/40] Update README.md --- README.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index daf39757b..07a29e7af 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,22 @@ Kindly report only issues/bugs here . For programming help or questions use [Sta * [API Documentation](https://justcoding121.github.io/Titanium-Web-Proxy/docs/api/Titanium.Web.Proxy.ProxyServer.html) * [Wiki & Contribution guidelines](https://github.com/justcoding121/Titanium-Web-Proxy/wiki) -**Console example application screenshot** +## Dev Environment +Development enviroment used to work and build this project is described below for each platforms. -![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG) +### Windows -**GUI example application screenshot** +* Visual Studio 2017 as IDE for .NET/.NET standard builds +* Visual Studio Code as IDE for .NET Standard only builds -![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG) + +### Mac OS + +* Visual Studio Code as IDE for .NET Standard only builds + +### Linux + +* Visual Studio Code as IDE for .NET Standard only builds ### Features @@ -229,3 +238,12 @@ public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs #### Collaborators * [honfika](https://github.com/honfika) + + +**Console example application screenshot** + +![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG) + +**GUI example application screenshot** + +![alt tag](https://raw.githubusercontent.com/justcoding121/Titanium-Web-Proxy/master/examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG) From 9334162b4f9015a0bdf0a017bccaa9d7e0531130 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 1 Sep 2018 09:49:09 -0400 Subject: [PATCH 06/40] Update README.md --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 07a29e7af..2247be4a1 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,6 @@ Kindly report only issues/bugs here . For programming help or questions use [Sta * [API Documentation](https://justcoding121.github.io/Titanium-Web-Proxy/docs/api/Titanium.Web.Proxy.ProxyServer.html) * [Wiki & Contribution guidelines](https://github.com/justcoding121/Titanium-Web-Proxy/wiki) -## Dev Environment -Development enviroment used to work and build this project is described below for each platforms. - -### Windows - -* Visual Studio 2017 as IDE for .NET/.NET standard builds -* Visual Studio Code as IDE for .NET Standard only builds - - -### Mac OS - -* Visual Studio Code as IDE for .NET Standard only builds - -### Linux - -* Visual Studio Code as IDE for .NET Standard only builds - ### Features * Multithreaded & fully asynchronous proxy employing server connection pooling, certificate cache & buffer pooling @@ -33,11 +16,7 @@ Development enviroment used to work and build this project is described below fo * Supports mutual SSL authentication, proxy authentication & automatic upstream proxy detection * Kerberos/NTLM authentication over HTTP protocols for windows domain -### Usage - - -Refer the HTTP Proxy Server library in your project, look up Test project to learn usage. - +### Installation Install by [nuget](https://www.nuget.org/packages/Titanium.Web.Proxy) For beta releases on [beta branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/beta) @@ -53,6 +32,27 @@ Supports * .Net Standard 2.0 or above * .Net Framework 4.5 or above +### Development Environment +Development enviroment used to work and build this project is described below for each platforms. + +#### Windows + +* Visual Studio 2017 as IDE for .NET/.NET standard builds +* Visual Studio Code as IDE for .NET Standard only builds + + +#### Mac OS + +* Visual Studio Code as IDE for .NET Standard only builds + +#### Linux + +* Visual Studio Code as IDE for .NET Standard only builds + +### Usage + +Refer the HTTP Proxy Server library in your project, look up Test project to learn usage. + Setup HTTP proxy: ```csharp From 2d898f12574edc57b9ba13d570c2ef1098fabfab Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 1 Sep 2018 09:52:46 -0400 Subject: [PATCH 07/40] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2247be4a1..dd46883b9 100644 --- a/README.md +++ b/README.md @@ -37,17 +37,15 @@ Development enviroment used to work and build this project is described below fo #### Windows -* Visual Studio 2017 as IDE for .NET/.NET standard builds -* Visual Studio Code as IDE for .NET Standard only builds - +* Visual Studio 2017/Visual Studio Code as IDE #### Mac OS -* Visual Studio Code as IDE for .NET Standard only builds +* Visual Studio Code as IDE for .NET Standard #### Linux -* Visual Studio Code as IDE for .NET Standard only builds +* Visual Studio Code as IDE for .NET Standard ### Usage From 8eecddb544d68f3662263fe1b77f1b32bfd0953a Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 1 Sep 2018 10:00:02 -0400 Subject: [PATCH 08/40] Update README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dd46883b9..caf549ecd 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,18 @@ Development enviroment used to work and build this project is described below fo #### Windows -* Visual Studio 2017/Visual Studio Code as IDE +* Visual Studio 2017 as IDE for .NET framework/.Net core +* Visual Studio Code as IDE for .NET core #### Mac OS -* Visual Studio Code as IDE for .NET Standard +* Visual Studio 2017 as IDE for Mono/.Net core +* Visual Studio Code as IDE for .NET core #### Linux -* Visual Studio Code as IDE for .NET Standard +* Visual Studio Code as IDE for .NET core +* Mono develop for Mono ### Usage From f68b24ccd293f91eb079298a565d5821b990335b Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 1 Sep 2018 10:02:51 -0400 Subject: [PATCH 09/40] Update README.md --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index caf549ecd..5424f7c45 100644 --- a/README.md +++ b/README.md @@ -36,19 +36,16 @@ Supports Development enviroment used to work and build this project is described below for each platforms. #### Windows - -* Visual Studio 2017 as IDE for .NET framework/.Net core -* Visual Studio Code as IDE for .NET core +* Visual Studio 2017 as IDE for .NET framework/.NET core +* Visual Studio Code as IDE for .NET framework/.NET core #### Mac OS - -* Visual Studio 2017 as IDE for Mono/.Net core +* Visual Studio 2017 as IDE for Mono/.NET core * Visual Studio Code as IDE for .NET core #### Linux - * Visual Studio Code as IDE for .NET core -* Mono develop for Mono +* Mono develop as IDE for Mono ### Usage From d7cec380c7615d80973044f48aa4739fca637d6b Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sun, 2 Sep 2018 16:54:29 -0400 Subject: [PATCH 10/40] exclude build --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 396246489..b508a250c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,7 +41,11 @@ skip_tags: true skip_commits: author: buildbot121 - + files: + - docs/* + - README.md + - LICENSE + #---------------------------------# # artifacts configuration # #---------------------------------# From 9b2c50c229ba5da377f73a2ce7791616928272f1 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 12:57:16 -0400 Subject: [PATCH 11/40] vscode proj --- .build/build.ps1 | 2 +- .vscode/launch.json | 27 +++++++++++++++++++ .vscode/settings.json | 13 +++++++++ .vscode/tasks.json | 26 ++++++++++++++++++ .../Titanium.Web.Proxy.Examples.Basic.csproj | 1 + .../Titanium.Web.Proxy.Examples.Wpf.csproj | 21 +++++++++++++++ src/Titanium.Web.Proxy.sln | 22 +++++++++++++++ .../Titanium.Web.Proxy.csproj | 1 + ...Titanium.Web.Proxy.IntegrationTests.csproj | 18 +++++++++++++ .../Titanium.Web.Proxy.UnitTests.csproj | 19 +++++++++++++ 10 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.build/build.ps1 b/.build/build.ps1 index e688cb481..6e588b1e6 100644 --- a/.build/build.ps1 +++ b/.build/build.ps1 @@ -58,7 +58,7 @@ Task Restore-Packages -depends Install-BuildTools { #build Task Build -depends Restore-Packages{ - exec { . $MSBuild $SolutionFile /t:Build /v:normal /p:Configuration=$Configuration /t:restore } + exec { . $MSBuild $SolutionFile /t:Build /v:normal /p:Configuration=$Configuration /p:Platform="Any CPU" /t:restore } } #publish API documentation changes for GitHub pages under master\docs directory diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..e64ad9186 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Net45|Debug|Basic Example", + "type": "clr", + "request": "launch", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/net45/Titanium.Web.Proxy.Examples.Basic.exe", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "console": "integratedTerminal", + "preLaunchTask": "build" + }, + { + "name": "Net45|Debug|Wpf Example", + "type": "clr", + "request": "launch", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Wpf/bin/x64/Debug/Titanium.Web.Proxy.Examples.Wpf.exe", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "console": "internalConsole", + "preLaunchTask": "build" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..af512f87f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + // The following will hide the js and map files in the editor + "files.exclude": { + "**/.build": true, + "**/.nuget": true, + "**/.vs": true, + "**/docs": true, + "**/packages": true, + "**/bin": true, + "**/obj": true, + "**/*.DotSettings": true, + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..7bcf370df --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "process", + "windows": { + "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", + "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=x64"] + }, + "osx": { + "command": "dotnet", + "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.DotNet.sln"] + }, + "linux": { + "command": "dotnet", + "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.DotNet.sln"] + }, + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file 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 9141a98c4..86c0c0f31 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 @@ -5,6 +5,7 @@ net45;netcoreapp2.0 false 7.1 + AnyCPU;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 f93a1569b..12327d6e3 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 @@ -50,6 +50,27 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.1 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + ..\..\packages\StreamExtended.1.0.179\lib\net45\StreamExtended.dll diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln index 25df39a28..769957aab 100644 --- a/src/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -41,29 +41,51 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|x64.ActiveCfg = Debug|x64 + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Debug|x64.Build.0 = Debug|x64 {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|Any CPU.Build.0 = Release|Any CPU + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|x64.ActiveCfg = Release|x64 + {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|x64.Build.0 = Release|x64 {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.ActiveCfg = Debug|x64 + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.Build.0 = Debug|x64 {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.Build.0 = Release|Any CPU + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.ActiveCfg = Release|x64 + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.Build.0 = Release|x64 {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|x64.ActiveCfg = Debug|x64 + {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|x64.Build.0 = Debug|x64 {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.ActiveCfg = Release|Any CPU {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.Build.0 = Release|Any CPU + {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|x64.ActiveCfg = Release|x64 + {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|x64.Build.0 = Release|x64 {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|x64.ActiveCfg = Debug|x64 + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|x64.Build.0 = Debug|x64 {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|Any CPU.Build.0 = Release|Any CPU + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|x64.ActiveCfg = Release|x64 + {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Release|x64.Build.0 = Release|x64 {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|x64.ActiveCfg = Debug|x64 + {4406CE17-9A39-4F28-8363-6169A4F799C1}.Debug|x64.Build.0 = Debug|x64 {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|Any CPU.Build.0 = Release|Any CPU + {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|x64.ActiveCfg = Release|x64 + {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj index 1ec2f81de..e4ac9802b 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj @@ -9,6 +9,7 @@ False True 7.1 + AnyCPU;x64 diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 83419f237..f3ddfd026 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -35,6 +35,24 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + diff --git a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj index 45d09949d..b89d06841 100644 --- a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj +++ b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj @@ -42,6 +42,25 @@ StrongNameKey.snk + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + From 774fae627234bd3e974a6efdee53fc8aa4249258 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 13:11:53 -0400 Subject: [PATCH 12/40] fix console launch --- .vscode/launch.json | 4 ++-- .vscode/tasks.json | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e64ad9186..6f05afd46 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "preLaunchTask": "build" }, { - "name": "Net45|Debug|Wpf Example", + "name": "Net45|Debug|Win|Wpf Example", "type": "clr", "request": "launch", "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Wpf/bin/x64/Debug/Titanium.Web.Proxy.Examples.Wpf.exe", @@ -21,7 +21,7 @@ "cwd": "${workspaceRoot}", "stopAtEntry": false, "console": "internalConsole", - "preLaunchTask": "build" + "preLaunchTask": "build-x64" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7bcf370df..8858272ee 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ "type": "process", "windows": { "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", - "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=x64"] + "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=Any CPU"] }, "osx": { "command": "dotnet", @@ -21,6 +21,17 @@ "kind": "build", "isDefault": true } + }, + { + "label": "build-x64", + "type": "process", + "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", + "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=x64"], + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } } ] } \ No newline at end of file From 21b97f5c0c683679f0adfdb3173a6b514201edeb Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 13:12:53 -0400 Subject: [PATCH 13/40] ignore vscode --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index b508a250c..8cecaa260 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,7 @@ skip_commits: author: buildbot121 files: - docs/* + - .vscode/* - README.md - LICENSE From 54ae2efc9b3269d42610a174dc514806cdbe3a41 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 13:16:45 -0400 Subject: [PATCH 14/40] fix wpf build --- .vscode/tasks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8858272ee..d19cf7bf8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -26,7 +26,7 @@ "label": "build-x64", "type": "process", "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", - "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=x64"], + "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj", "/p:Platform=x64"], "problemMatcher": "$msCompile", "group": { "kind": "build", From 380de7ed228424da74e54bf7484abdd6f0220d6d Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 13:17:35 -0400 Subject: [PATCH 15/40] fix names --- .vscode/launch.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6f05afd46..48231ad10 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Net45|Debug|Basic Example", + "name": "Win|Net45|Debug|Basic Example", "type": "clr", "request": "launch", "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/net45/Titanium.Web.Proxy.Examples.Basic.exe", @@ -13,7 +13,7 @@ "preLaunchTask": "build" }, { - "name": "Net45|Debug|Win|Wpf Example", + "name": "Win|Net45|Debug|Wpf Example", "type": "clr", "request": "launch", "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Wpf/bin/x64/Debug/Titanium.Web.Proxy.Examples.Wpf.exe", From 43d526b07382b51c884f713c5e7fab6d9e693676 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 13:21:11 -0400 Subject: [PATCH 16/40] sln exclude --- .vscode/launch.json | 4 ++-- .vscode/settings.json | 1 + .vscode/tasks.json | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 48231ad10..c89dd4704 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "cwd": "${workspaceRoot}", "stopAtEntry": false, "console": "integratedTerminal", - "preLaunchTask": "build" + "preLaunchTask": "build-basic-example" }, { "name": "Win|Net45|Debug|Wpf Example", @@ -21,7 +21,7 @@ "cwd": "${workspaceRoot}", "stopAtEntry": false, "console": "internalConsole", - "preLaunchTask": "build-x64" + "preLaunchTask": "build-wpf-example" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index af512f87f..c3e5daedd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ "**/bin": true, "**/obj": true, "**/*.DotSettings": true, + "**/*.sln": true, } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d19cf7bf8..3321b29b2 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,11 +2,11 @@ "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "build-basic-example", "type": "process", "windows": { "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", - "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.sln", "/p:Platform=Any CPU"] + "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj", "/p:Platform=Any CPU"] }, "osx": { "command": "dotnet", @@ -23,7 +23,7 @@ } }, { - "label": "build-x64", + "label": "build-wpf-example", "type": "process", "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj", "/p:Platform=x64"], From 14709ac41bf7642e7a241489b711a16f11ff3f06 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 19:38:35 -0400 Subject: [PATCH 17/40] add core build task --- .vscode/launch.json | 17 ++++++++++++++--- .vscode/tasks.json | 25 ++++++++++++++----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index c89dd4704..ddc747a92 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,18 @@ "version": "0.2.0", "configurations": [ { - "name": "Win|Net45|Debug|Basic Example", + "name": "NetCore|Debug|Basic Example", + "type": "coreclr", + "request": "launch", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.dll", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "console": "internalConsole", + "preLaunchTask": "build-basic-example-netcore" + }, + { + "name": "Windows|Net45|Debug|Basic Example", "type": "clr", "request": "launch", "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/net45/Titanium.Web.Proxy.Examples.Basic.exe", @@ -10,10 +21,10 @@ "cwd": "${workspaceRoot}", "stopAtEntry": false, "console": "integratedTerminal", - "preLaunchTask": "build-basic-example" + "preLaunchTask": "build-basic-example-net45" }, { - "name": "Win|Net45|Debug|Wpf Example", + "name": "Windows|Net45|Debug|Wpf Example", "type": "clr", "request": "launch", "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Wpf/bin/x64/Debug/Titanium.Web.Proxy.Examples.Wpf.exe", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3321b29b2..001c8ffb9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,7 +2,18 @@ "version": "2.0.0", "tasks": [ { - "label": "build-basic-example", + "label": "build-basic-example-netcore", + "type": "process", + "command": "dotnet", + "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj"], + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "build-basic-example-net45", "type": "process", "windows": { "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", @@ -16,22 +27,14 @@ "command": "dotnet", "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.DotNet.sln"] }, - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } + "problemMatcher": "$msCompile" }, { "label": "build-wpf-example", "type": "process", "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj", "/p:Platform=x64"], - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } + "problemMatcher": "$msCompile" } ] } \ No newline at end of file From 99dbaeeb597a7c9d45aca6de774639bfaa7690b6 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 19:48:04 -0400 Subject: [PATCH 18/40] docfx path fix --- .build/docfx.json | 2 +- src/Titanium.Web.Proxy.Docs.sln | 7 ------- src/Titanium.Web.Proxy.sln | 9 +-------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/.build/docfx.json b/.build/docfx.json index c11b92915..72947799a 100644 --- a/.build/docfx.json +++ b/.build/docfx.json @@ -4,7 +4,7 @@ "src": [ { "files": [ "Titanium.Web.Proxy.Docs.sln"], - "src": "../" + "src": "../src/" } ], "dest": "obj/api" diff --git a/src/Titanium.Web.Proxy.Docs.sln b/src/Titanium.Web.Proxy.Docs.sln index e2a2a410d..a4f980f42 100644 --- a/src/Titanium.Web.Proxy.Docs.sln +++ b/src/Titanium.Web.Proxy.Docs.sln @@ -3,13 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27428.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B84B-9283-4E9C-8C43-A234E9AA3EAA}" - ProjectSection(SolutionItems) = preProject - ..\.nuget\NuGet.Config = ..\.nuget\NuGet.Config - ..\.nuget\NuGet.exe = ..\.nuget\NuGet.exe - ..\.nuget\NuGet.targets = ..\.nuget\NuGet.targets - EndProjectSection -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Docs", "Titanium.Web.Proxy\Titanium.Web.Proxy.Docs.csproj", "{EBF2EA46-EA00-4350-BE1D-D86AFD699DB3}" EndProject Global diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln index 769957aab..34eb45ecc 100644 --- a/src/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -5,13 +5,6 @@ VisualStudioVersion = 15.0.26906.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{B6DBABDC-C985-4872-9C38-B4E5079CBC4B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B84B-9283-4E9C-8C43-A234E9AA3EAA}" - ProjectSection(SolutionItems) = preProject - ..\.nuget\NuGet.Config = ..\.nuget\NuGet.Config - ..\.nuget\NuGet.exe = ..\.nuget\NuGet.exe - ..\.nuget\NuGet.targets = ..\.nuget\NuGet.targets - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{38EA62D0-D2CB-465D-AF4F-407C5B4D4A1E}" ProjectSection(SolutionItems) = preProject ..\LICENSE = ..\LICENSE @@ -97,7 +90,7 @@ Global {4406CE17-9A39-4F28-8363-6169A4F799C1} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A} EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 + SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A} EndGlobalSection EndGlobal From b5b0b4ac05c4b9121de5bbb1d8458c935808608c Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 20:13:32 -0400 Subject: [PATCH 19/40] ominisharp exlude docs proj from building --- .vscode/launch.json | 2 +- .vscode/settings.json | 16 +++++++++++++++- omnisharp.json | 7 +++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 omnisharp.json diff --git a/.vscode/launch.json b/.vscode/launch.json index ddc747a92..1a68fcde2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, - "console": "internalConsole", + "console": "integratedTerminal", "preLaunchTask": "build-basic-example-netcore" }, { diff --git a/.vscode/settings.json b/.vscode/settings.json index c3e5daedd..6f6985268 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,20 @@ "**/bin": true, "**/obj": true, "**/*.DotSettings": true, - "**/*.sln": true, + "**/*.sln": true + }, + "search.exclude": { + // The following will hide the js and map files in the editor + "files.exclude": { + "**/.build": true, + "**/.nuget": true, + "**/.vs": true, + "**/docs": true, + "**/packages": true, + "**/bin": true, + "**/obj": true, + "**/*.DotSettings": true, + "**/*.sln": true + } } } \ No newline at end of file diff --git a/omnisharp.json b/omnisharp.json new file mode 100644 index 000000000..b97bfe1e6 --- /dev/null +++ b/omnisharp.json @@ -0,0 +1,7 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/*.Docs.csproj" + ] + } + } \ No newline at end of file From b0569809941af6fd0936fd956e8704d0b8c1d638 Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Mon, 3 Sep 2018 16:49:58 -0700 Subject: [PATCH 20/40] API documentation update by build server --- .../Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html | 2 +- ...Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html | 2 +- ....Web.Proxy.EventArguments.CertificateSelectionEventArgs.html | 2 +- ...Web.Proxy.EventArguments.CertificateValidationEventArgs.html | 2 +- ....Proxy.EventArguments.MultipartRequestPartSentEventArgs.html | 2 +- .../api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html | 2 +- .../Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html | 2 +- ....Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html | 2 +- docs/api/Titanium.Web.Proxy.EventArguments.html | 2 +- docs/api/Titanium.Web.Proxy.ExceptionHandler.html | 2 +- .../Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html | 2 +- ...tanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html | 2 +- docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html | 2 +- docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html | 2 +- docs/api/Titanium.Web.Proxy.Exceptions.html | 2 +- docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html | 2 +- docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html | 2 +- docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html | 2 +- docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html | 2 +- docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Request.html | 2 +- docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Response.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html | 2 +- .../api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Responses.html | 2 +- docs/api/Titanium.Web.Proxy.Http.html | 2 +- docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html | 2 +- docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html | 2 +- docs/api/Titanium.Web.Proxy.Models.HttpHeader.html | 2 +- docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html | 2 +- .../api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html | 2 +- docs/api/Titanium.Web.Proxy.Models.html | 2 +- docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html | 2 +- docs/api/Titanium.Web.Proxy.Network.CertificateManager.html | 2 +- docs/api/Titanium.Web.Proxy.Network.html | 2 +- docs/api/Titanium.Web.Proxy.ProxyServer.html | 2 +- docs/api/Titanium.Web.Proxy.html | 2 +- 39 files changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html b/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html index b55dc7bcb..a2bab66f9 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html index 902fcb6f3..855d1e692 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html index e5e1bd3d6..2d68bb8a4 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html index 95c9c871d..7f4d6ba27 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html index be4375204..1ce04ed84 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html index 643f567ad..942253ce2 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html index 8d9271980..dc6ef6f11 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html index c326bcdac..901a2be9b 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.html b/docs/api/Titanium.Web.Proxy.EventArguments.html index a59a9a839..1dd02f117 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.ExceptionHandler.html b/docs/api/Titanium.Web.Proxy.ExceptionHandler.html index d7db8b863..1c5152cfd 100644 --- a/docs/api/Titanium.Web.Proxy.ExceptionHandler.html +++ b/docs/api/Titanium.Web.Proxy.ExceptionHandler.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html b/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html index b1726a639..04bc0c4bf 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html index e2f9afe6b..f4062b3c7 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html index ec4c2255f..75a6fb9cd 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html index 5f0551b84..a1b16ff50 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.html b/docs/api/Titanium.Web.Proxy.Exceptions.html index 9a2b93e92..345784637 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html b/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html index e8ed8bc8a..e0a45ed92 100644 --- a/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html +++ b/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html b/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html index ae1f281aa..9bb0aa8e2 100644 --- a/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html b/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html index d052a84e1..b7f1d3e98 100644 --- a/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html +++ b/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html b/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html index 9719909c4..027c52388 100644 --- a/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html +++ b/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html b/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html index 9fbd7efe8..cd013c1a1 100644 --- a/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html +++ b/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Request.html b/docs/api/Titanium.Web.Proxy.Http.Request.html index 710d5a2c2..904349249 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Request.html +++ b/docs/api/Titanium.Web.Proxy.Http.Request.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html b/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html index 42c9870dd..0921a7e85 100644 --- a/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html +++ b/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Response.html b/docs/api/Titanium.Web.Proxy.Http.Response.html index 41f41af41..0a58d6871 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Response.html +++ b/docs/api/Titanium.Web.Proxy.Http.Response.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html index fc7fde99d..fd401c31d 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html index 4321effa8..21fdfa876 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html index e1506b8a7..233d77f97 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.html b/docs/api/Titanium.Web.Proxy.Http.Responses.html index 65668ffb2..f94bec476 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.html b/docs/api/Titanium.Web.Proxy.Http.html index f9676618e..56ffec05d 100644 --- a/docs/api/Titanium.Web.Proxy.Http.html +++ b/docs/api/Titanium.Web.Proxy.Http.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html index 56960f231..402ac1598 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html b/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html index 67138f088..d7edcacc1 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html +++ b/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html b/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html index a1214ffbc..20b8ecb71 100644 --- a/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html +++ b/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html index 31341bf95..0c5f2c7e7 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html index 8207f9667..86e5af103 100644 --- a/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.html b/docs/api/Titanium.Web.Proxy.Models.html index 728bb914d..91962da07 100644 --- a/docs/api/Titanium.Web.Proxy.Models.html +++ b/docs/api/Titanium.Web.Proxy.Models.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html b/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html index 8e4523bdd..ea9d80e34 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html index 2e4bd36f9..81f497b9e 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.html b/docs/api/Titanium.Web.Proxy.Network.html index d6449a2cd..d81b62e16 100644 --- a/docs/api/Titanium.Web.Proxy.Network.html +++ b/docs/api/Titanium.Web.Proxy.Network.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index 379c47878..1c1704c1a 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.html b/docs/api/Titanium.Web.Proxy.html index 22d62e9ef..edcd6ca93 100644 --- a/docs/api/Titanium.Web.Proxy.html +++ b/docs/api/Titanium.Web.Proxy.html @@ -10,7 +10,7 @@ - + From 17a85d995dc78f725fed236dab992c4834e6f24b Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 20:41:57 -0400 Subject: [PATCH 21/40] macOS fixes --- .vscode/launch.json | 22 ----------- .vscode/settings.json | 13 ++++--- .vscode/tasks.json | 26 +------------ .../Program.cs | 8 +++- ...um.Web.Proxy.Examples.Basic.NetCore.csproj | 19 ++++++++++ omnisharp.json | 5 ++- src/Titanium.Web.Proxy/Helpers/RunTime.cs | 37 +++++++------------ 7 files changed, 51 insertions(+), 79 deletions(-) create mode 100644 examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj diff --git a/.vscode/launch.json b/.vscode/launch.json index 1a68fcde2..6f86ecde0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,28 +11,6 @@ "stopAtEntry": false, "console": "integratedTerminal", "preLaunchTask": "build-basic-example-netcore" - }, - { - "name": "Windows|Net45|Debug|Basic Example", - "type": "clr", - "request": "launch", - "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/net45/Titanium.Web.Proxy.Examples.Basic.exe", - "args": [], - "cwd": "${workspaceRoot}", - "stopAtEntry": false, - "console": "integratedTerminal", - "preLaunchTask": "build-basic-example-net45" - }, - { - "name": "Windows|Net45|Debug|Wpf Example", - "type": "clr", - "request": "launch", - "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Wpf/bin/x64/Debug/Titanium.Web.Proxy.Examples.Wpf.exe", - "args": [], - "cwd": "${workspaceRoot}", - "stopAtEntry": false, - "console": "internalConsole", - "preLaunchTask": "build-wpf-example" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 6f6985268..ebf625a2d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,11 +9,12 @@ "**/bin": true, "**/obj": true, "**/*.DotSettings": true, - "**/*.sln": true + "**/*.sln": true, + "**/tests/" : true, + "**/Titanium.Web.Proxy.Examples.Wpf/" : true, + "**/*.Basic.csproj/": true }, "search.exclude": { - // The following will hide the js and map files in the editor - "files.exclude": { "**/.build": true, "**/.nuget": true, "**/.vs": true, @@ -22,7 +23,9 @@ "**/bin": true, "**/obj": true, "**/*.DotSettings": true, - "**/*.sln": true - } + "**/*.sln": true, + "**/tests/" : true, + "**/Titanium.Web.Proxy.Examples.Wpf/" : true, + "**/*.Basic.csproj/": true } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 001c8ffb9..48fec60eb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,36 +5,12 @@ "label": "build-basic-example-netcore", "type": "process", "command": "dotnet", - "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj"], + "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj"], "problemMatcher": "$msCompile", "group": { "kind": "build", "isDefault": true } - }, - { - "label": "build-basic-example-net45", - "type": "process", - "windows": { - "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", - "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj", "/p:Platform=Any CPU"] - }, - "osx": { - "command": "dotnet", - "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.DotNet.sln"] - }, - "linux": { - "command": "dotnet", - "args": ["${workspaceFolder}/src/Titanium.Web.Proxy.DotNet.sln"] - }, - "problemMatcher": "$msCompile" - }, - { - "label": "build-wpf-example", - "type": "process", - "command": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe", - "args": ["${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj", "/p:Platform=x64"], - "problemMatcher": "$msCompile" } ] } \ No newline at end of file diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs b/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs index 06fe4fce3..d0a1ee2c9 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; using Titanium.Web.Proxy.Examples.Basic.Helpers; namespace Titanium.Web.Proxy.Examples.Basic @@ -9,8 +10,11 @@ public class Program public static void Main(string[] args) { - // fix console hang due to QuickEdit mode - ConsoleHelper.DisableQuickEditMode(); + if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // fix console hang due to QuickEdit mode + ConsoleHelper.DisableQuickEditMode(); + } // Start proxy controller controller.StartProxy(); diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj new file mode 100644 index 000000000..6649c2b7f --- /dev/null +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj @@ -0,0 +1,19 @@ + + + + Exe + netcoreapp2.0 + false + 7.1 + AnyCPU;x64 + + + + + + + + + + + \ No newline at end of file diff --git a/omnisharp.json b/omnisharp.json index b97bfe1e6..8b2190cb7 100644 --- a/omnisharp.json +++ b/omnisharp.json @@ -1,7 +1,10 @@ { "fileOptions": { "excludeSearchPatterns": [ - "**/*.Docs.csproj" + "**/*.Docs.csproj", + "**/tests/", + "**/Titanium.Web.Proxy.Examples.Wpf/", + "**/*.Basic.csproj/" ] } } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs index ba70e7b2c..61e2c063e 100644 --- a/src/Titanium.Web.Proxy/Helpers/RunTime.cs +++ b/src/Titanium.Web.Proxy/Helpers/RunTime.cs @@ -1,8 +1,6 @@ using System; - -#if NETSTANDARD2_0 using System.Runtime.InteropServices; -#endif + namespace Titanium.Web.Proxy.Helpers { /// @@ -16,33 +14,24 @@ internal class RunTime /// private static readonly Lazy isRunningOnMono = new Lazy(() => Type.GetType("Mono.Runtime") != null); -#if NETSTANDARD2_0 -/// -/// cache for Windows platform check -/// -/// -private static readonly Lazy isRunningOnWindows - = new Lazy(() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); - -private static readonly Lazy isRunningOnLinux - = new Lazy(() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux)); -#endif + /// + /// cache for Windows platform check + /// + /// + private static bool isRunningOnWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + private static bool isRunningOnLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + private static bool isRunningOnMac => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); /// /// Is running on Mono? /// internal static bool IsRunningOnMono => isRunningOnMono.Value; -#if NETSTANDARD2_0 - internal static bool IsLinux => isRunningOnLinux.Value; -#else - internal static bool IsLinux => !IsWindows; -#endif + internal static bool IsLinux => isRunningOnLinux; + + internal static bool IsWindows => isRunningOnWindows; + + internal static bool IsMac => isRunningOnMac; -#if NETSTANDARD2_0 - internal static bool IsWindows => isRunningOnWindows.Value; -#else - internal static bool IsWindows => true; -#endif } } From 4728bc4c0dd44ab76eaa795b2c40ca9af263f969 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 20:50:52 -0400 Subject: [PATCH 22/40] fix exclusion --- omnisharp.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/omnisharp.json b/omnisharp.json index 8b2190cb7..ca4ca39a5 100644 --- a/omnisharp.json +++ b/omnisharp.json @@ -4,7 +4,7 @@ "**/*.Docs.csproj", "**/tests/", "**/Titanium.Web.Proxy.Examples.Wpf/", - "**/*.Basic.csproj/" + "**/*.Basic.csproj" ] } } \ No newline at end of file From 852f257f330244184667cf7c95164e124de4f4f7 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 20:57:19 -0400 Subject: [PATCH 23/40] netcore proj --- .vscode/settings.json | 8 ++- ...um.Web.Proxy.Examples.Basic.NetCore.csproj | 1 - omnisharp.json | 3 +- .../Titanium.Web.Proxy.NetCore.csproj | 65 +++++++++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj diff --git a/.vscode/settings.json b/.vscode/settings.json index ebf625a2d..329486332 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,9 @@ "**/*.sln": true, "**/tests/" : true, "**/Titanium.Web.Proxy.Examples.Wpf/" : true, - "**/*.Basic.csproj/": true + "**/*.Basic.csproj/": true, + "**/*.Docs.csproj/": true, + "**/*.Proxy.csproj/": true }, "search.exclude": { "**/.build": true, @@ -26,6 +28,8 @@ "**/*.sln": true, "**/tests/" : true, "**/Titanium.Web.Proxy.Examples.Wpf/" : true, - "**/*.Basic.csproj/": true + "**/*.Basic.csproj/": true, + "**/*.Docs.csproj/": true, + "**/*.Proxy.csproj/": true } } \ No newline at end of file diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj index 6649c2b7f..583deef71 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj @@ -5,7 +5,6 @@ netcoreapp2.0 false 7.1 - AnyCPU;x64 diff --git a/omnisharp.json b/omnisharp.json index ca4ca39a5..de8d40bba 100644 --- a/omnisharp.json +++ b/omnisharp.json @@ -4,7 +4,8 @@ "**/*.Docs.csproj", "**/tests/", "**/Titanium.Web.Proxy.Examples.Wpf/", - "**/*.Basic.csproj" + "**/*.Basic.csproj", + "**/*.Proxy.csproj" ] } } \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj new file mode 100644 index 000000000..e4ac9802b --- /dev/null +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj @@ -0,0 +1,65 @@ + + + + net45;netstandard2.0 + Titanium.Web.Proxy + false + True + StrongNameKey.snk + False + True + 7.1 + AnyCPU;x64 + + + + + + + + + + 4.4.0 + + + 4.4.1 + + + + + + 4.4.0 + + + 4.4.1 + + + + + + + + + + True + True + + + True + True + + + True + True + + + True + True + + + True + True + + + + \ No newline at end of file From f54ae788dd692f7bdd44d67731f6bdce9a62b115 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 21:30:31 -0400 Subject: [PATCH 24/40] rm net45 --- src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj index e4ac9802b..71311c000 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj @@ -1,7 +1,7 @@  - net45;netstandard2.0 + netstandard2.0 Titanium.Web.Proxy false True From 897b7b54b67aef46c01955d547cec5eb95ddd96c Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 21:48:01 -0400 Subject: [PATCH 25/40] fix launch --- .vscode/launch.json | 2 +- .../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6f86ecde0..cd3c24d6f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "NetCore|Debug|Basic Example", "type": "coreclr", "request": "launch", - "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.dll", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index b842853ed..e4a9bf4a9 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -10,6 +10,7 @@ using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Models; +using System.Runtime.InteropServices; namespace Titanium.Web.Proxy.Examples.Basic { @@ -108,9 +109,8 @@ public void StartProxy() endPoint.IpAddress, endPoint.Port); } -#if NETSTANDARD2_0 + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) -#endif { // Only explicit proxies can be set as system proxy! //proxyServer.SetAsSystemHttpProxy(explicitEndPoint); From c7a1ff758f3bea5669e6ff7490e0baca675946e2 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 21:57:11 -0400 Subject: [PATCH 26/40] rm platform --- src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj index 71311c000..354e6e112 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj @@ -9,7 +9,6 @@ False True 7.1 - AnyCPU;x64 From 39d351dc403499c6c50f7c861d539eb42b46e6a7 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 22:26:29 -0400 Subject: [PATCH 27/40] fix operating system checks --- .../Program.cs | 7 ++-- .../ProxyTestController.cs | 10 ++--- src/Titanium.Web.Proxy/Helpers/RunTime.cs | 37 ++++++++++++++++--- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs b/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs index d0a1ee2c9..11829c123 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Program.cs @@ -1,6 +1,6 @@ using System; -using System.Runtime.InteropServices; using Titanium.Web.Proxy.Examples.Basic.Helpers; +using Titanium.Web.Proxy.Helpers; namespace Titanium.Web.Proxy.Examples.Basic { @@ -10,9 +10,10 @@ public class Program public static void Main(string[] args) { - if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + + if (RunTime.IsWindows) { - // fix console hang due to QuickEdit mode + // fix console hang due to QuickEdit mode ConsoleHelper.DisableQuickEditMode(); } diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index e4a9bf4a9..dfdfd243e 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -10,7 +10,6 @@ using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Models; -using System.Runtime.InteropServices; namespace Titanium.Web.Proxy.Examples.Basic { @@ -109,12 +108,11 @@ public void StartProxy() endPoint.IpAddress, endPoint.Port); } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // Only explicit proxies can be set as system proxy! + //proxyServer.SetAsSystemHttpProxy(explicitEndPoint); + //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); + if(RunTime.IsWindows) { - // Only explicit proxies can be set as system proxy! - //proxyServer.SetAsSystemHttpProxy(explicitEndPoint); - //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); } } diff --git a/src/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs index 61e2c063e..d34dd45f6 100644 --- a/src/Titanium.Web.Proxy/Helpers/RunTime.cs +++ b/src/Titanium.Web.Proxy/Helpers/RunTime.cs @@ -1,12 +1,14 @@ using System; +#if NETSTANDARD2_0 using System.Runtime.InteropServices; +#endif namespace Titanium.Web.Proxy.Helpers { /// /// Run time helpers /// - internal class RunTime + public static class RunTime { /// /// cache for mono runtime check @@ -14,6 +16,19 @@ internal class RunTime /// private static readonly Lazy isRunningOnMono = new Lazy(() => Type.GetType("Mono.Runtime") != null); + /// + /// cache for mono runtime check + /// + /// + private static readonly Lazy isRunningOnMonoLinux = new Lazy(() => IsRunningOnMono && (int)Environment.OSVersion.Platform == 4); + + /// + /// cache for mono runtime check + /// + /// + private static readonly Lazy isRunningOnMonoMac = new Lazy(() => IsRunningOnMono && (int)Environment.OSVersion.Platform == 6); + +#if NETSTANDARD2_0 /// /// cache for Windows platform check /// @@ -21,17 +36,29 @@ internal class RunTime private static bool isRunningOnWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); private static bool isRunningOnLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux); private static bool isRunningOnMac => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - +#endif /// /// Is running on Mono? /// internal static bool IsRunningOnMono => isRunningOnMono.Value; - internal static bool IsLinux => isRunningOnLinux; +#if NETSTANDARD2_0 + public static bool IsLinux => isRunningOnLinux; +#else + public static bool IsLinux => isRunningOnMonoLinux.Value; +#endif - internal static bool IsWindows => isRunningOnWindows; +#if NETSTANDARD2_0 + public static bool IsWindows => isRunningOnWindows; +#else + public static bool IsWindows => !IsLinux && !IsMac; +#endif - internal static bool IsMac => isRunningOnMac; +#if NETSTANDARD2_0 + public static bool IsMac => isRunningOnMac; +#else + public static bool IsMac => isRunningOnMonoMac.Value; +#endif } } From 3afe7c28356a3378a05931aa0077863f167e159c Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 22:31:44 -0400 Subject: [PATCH 28/40] fix reference --- .../Titanium.Web.Proxy.Examples.Basic.NetCore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj index 583deef71..9cfd6300b 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj @@ -12,7 +12,7 @@ - + \ No newline at end of file From f1dd35d3ff59b78861cefbaefccf1925e1f1d7d4 Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Mon, 3 Sep 2018 19:29:13 -0700 Subject: [PATCH 29/40] API documentation update by build server --- .../Titanium.Web.Proxy.Helpers.RunTime.html | 236 ++++++++++++++++++ docs/api/Titanium.Web.Proxy.Helpers.html | 9 +- docs/api/toc.html | 10 + docs/index.json | 10 + docs/xrefmap.yml | 51 ++++ 5 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 docs/api/Titanium.Web.Proxy.Helpers.RunTime.html diff --git a/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html b/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html new file mode 100644 index 000000000..40379c3a4 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html @@ -0,0 +1,236 @@ + + + + + + + + Class RunTime + | Titanium Web Proxy + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + + + +
+
+
+
+ +
+
+
+
+
+ +
+
+
    +
  • +
+
+
+
+
+ +
+
+
+

+
+
    +
    +
    +
    + +
    + Show / Hide Table of Contents +
    +
    +
    +
    +
    +
    +
    + + +

    Class RunTime +

    +

    Run time helpers

    +
    +
    +
    +
    Inheritance
    +
    Object
    +
    RunTime
    +
    +
    +
    Inherited Members
    +
    + Object.ToString() +
    +
    + Object.Equals(Object) +
    +
    + Object.Equals(Object, Object) +
    +
    + Object.ReferenceEquals(Object, Object) +
    +
    + Object.GetHashCode() +
    +
    + Object.GetType() +
    +
    + Object.MemberwiseClone() +
    +
    +
    Namespace: Titanium.Web.Proxy.Helpers
    +
    Assembly: Titanium.Web.Proxy.dll
    +
    Syntax
    +
    +
    public static class RunTime
    +
    +

    Properties +

    + + + +

    IsLinux

    +
    +
    +
    Declaration
    +
    +
    public static bool IsLinux { get; }
    +
    +
    Property Value
    + + + + + + + + + + + + + +
    TypeDescription
    Boolean
    + + + +

    IsMac

    +
    +
    +
    Declaration
    +
    +
    public static bool IsMac { get; }
    +
    +
    Property Value
    + + + + + + + + + + + + + +
    TypeDescription
    Boolean
    + + + +

    IsWindows

    +
    +
    +
    Declaration
    +
    +
    public static bool IsWindows { get; }
    +
    +
    Property Value
    + + + + + + + + + + + + + +
    TypeDescription
    Boolean
    +
    +
    + +
    +
    +
    +
      +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + Back to top + + + Generated by DocFX +
    +
    +
    +
    + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Helpers.html b/docs/api/Titanium.Web.Proxy.Helpers.html index ad31a10ec..e4d4a6d70 100644 --- a/docs/api/Titanium.Web.Proxy.Helpers.html +++ b/docs/api/Titanium.Web.Proxy.Helpers.html @@ -10,7 +10,7 @@ - + @@ -85,10 +85,11 @@

    -

    Enums +

    Classes

    -

    ProxyProtocolType

    -
    +

    RunTime

    +

    Run time helpers

    +
    diff --git a/docs/api/toc.html b/docs/api/toc.html index a34a0a15a..01d092c49 100644 --- a/docs/api/toc.html +++ b/docs/api/toc.html @@ -74,6 +74,16 @@ +
  • + + Titanium.Web.Proxy.Helpers + +
      +
    • + RunTime +
    • +
    +
  • Titanium.Web.Proxy.Http diff --git a/docs/index.json b/docs/index.json index e09fda245..081247232 100644 --- a/docs/index.json +++ b/docs/index.json @@ -74,6 +74,16 @@ "title": "Class ProxyHttpException | Titanium Web Proxy", "keywords": "Class ProxyHttpException Proxy HTTP exception. Inheritance Object Exception ProxyException ProxyHttpException Implements ISerializable _Exception Inherited Members Exception.GetBaseException() Exception.ToString() Exception.GetObjectData(SerializationInfo, StreamingContext) Exception.GetType() Exception.Message Exception.Data Exception.InnerException Exception.TargetSite Exception.StackTrace Exception.HelpLink Exception.Source Exception.HResult Exception.SerializeObjectState Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Exceptions Assembly : Titanium.Web.Proxy.dll Syntax public class ProxyHttpException : ProxyException, ISerializable, _Exception Properties SessionEventArgs Gets session info associated to the exception. Declaration public SessionEventArgs SessionEventArgs { get; } Property Value Type Description SessionEventArgs Remarks This object properties should not be edited. Implements System.Runtime.Serialization.ISerializable System.Runtime.InteropServices._Exception" }, + "api/Titanium.Web.Proxy.Helpers.html": { + "href": "api/Titanium.Web.Proxy.Helpers.html", + "title": "Namespace Titanium.Web.Proxy.Helpers | Titanium Web Proxy", + "keywords": "Namespace Titanium.Web.Proxy.Helpers Classes RunTime Run time helpers" + }, + "api/Titanium.Web.Proxy.Helpers.RunTime.html": { + "href": "api/Titanium.Web.Proxy.Helpers.RunTime.html", + "title": "Class RunTime | Titanium Web Proxy", + "keywords": "Class RunTime Run time helpers Inheritance Object RunTime Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Helpers Assembly : Titanium.Web.Proxy.dll Syntax public static class RunTime Properties IsLinux Declaration public static bool IsLinux { get; } Property Value Type Description Boolean IsMac Declaration public static bool IsMac { get; } Property Value Type Description Boolean IsWindows Declaration public static bool IsWindows { get; } Property Value Type Description Boolean" + }, "api/Titanium.Web.Proxy.html": { "href": "api/Titanium.Web.Proxy.html", "title": "Namespace Titanium.Web.Proxy | Titanium Web Proxy", diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index 1c0bebc56..68da43ef4 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -822,6 +822,57 @@ references: isSpec: "True" fullName: Titanium.Web.Proxy.Exceptions.ProxyHttpException.SessionEventArgs nameWithType: ProxyHttpException.SessionEventArgs +- uid: Titanium.Web.Proxy.Helpers + name: Titanium.Web.Proxy.Helpers + href: api/Titanium.Web.Proxy.Helpers.html + commentId: N:Titanium.Web.Proxy.Helpers + fullName: Titanium.Web.Proxy.Helpers + nameWithType: Titanium.Web.Proxy.Helpers +- uid: Titanium.Web.Proxy.Helpers.RunTime + name: RunTime + href: api/Titanium.Web.Proxy.Helpers.RunTime.html + commentId: T:Titanium.Web.Proxy.Helpers.RunTime + fullName: Titanium.Web.Proxy.Helpers.RunTime + nameWithType: RunTime +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsLinux + name: IsLinux + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsLinux + commentId: P:Titanium.Web.Proxy.Helpers.RunTime.IsLinux + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsLinux + nameWithType: RunTime.IsLinux +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsLinux* + name: IsLinux + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsLinux_ + commentId: Overload:Titanium.Web.Proxy.Helpers.RunTime.IsLinux + isSpec: "True" + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsLinux + nameWithType: RunTime.IsLinux +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsMac + name: IsMac + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsMac + commentId: P:Titanium.Web.Proxy.Helpers.RunTime.IsMac + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsMac + nameWithType: RunTime.IsMac +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsMac* + name: IsMac + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsMac_ + commentId: Overload:Titanium.Web.Proxy.Helpers.RunTime.IsMac + isSpec: "True" + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsMac + nameWithType: RunTime.IsMac +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsWindows + name: IsWindows + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsWindows + commentId: P:Titanium.Web.Proxy.Helpers.RunTime.IsWindows + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsWindows + nameWithType: RunTime.IsWindows +- uid: Titanium.Web.Proxy.Helpers.RunTime.IsWindows* + name: IsWindows + href: api/Titanium.Web.Proxy.Helpers.RunTime.html#Titanium_Web_Proxy_Helpers_RunTime_IsWindows_ + commentId: Overload:Titanium.Web.Proxy.Helpers.RunTime.IsWindows + isSpec: "True" + fullName: Titanium.Web.Proxy.Helpers.RunTime.IsWindows + nameWithType: RunTime.IsWindows - uid: Titanium.Web.Proxy.Http name: Titanium.Web.Proxy.Http href: api/Titanium.Web.Proxy.Http.html From ab4676894f7f0a9d1f9c61e797c7f5180a4f3619 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 23:40:01 -0400 Subject: [PATCH 30/40] mono sln --- ...anium.Web.Proxy.Examples.Basic.Mono.csproj | 15 +++++ src/Titanium.Web.Proxy.Mono.sln | 61 +++++++++++++++++++ .../Titanium.Web.Proxy.Mono.csproj | 48 +++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj create mode 100644 src/Titanium.Web.Proxy.Mono.sln create mode 100644 src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj new file mode 100644 index 000000000..88075afe5 --- /dev/null +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj @@ -0,0 +1,15 @@ + + + + Exe + net45 + false + 7.1 + AnyCPU;x64 + + + + + + + \ No newline at end of file diff --git a/src/Titanium.Web.Proxy.Mono.sln b/src/Titanium.Web.Proxy.Mono.sln new file mode 100644 index 000000000..4914496df --- /dev/null +++ b/src/Titanium.Web.Proxy.Mono.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26906.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{B6DBABDC-C985-4872-9C38-B4E5079CBC4B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{38EA62D0-D2CB-465D-AF4F-407C5B4D4A1E}" + ProjectSection(SolutionItems) = preProject + ..\LICENSE = ..\LICENSE + ..\PULL_REQUEST_TEMPLATE.md = ..\PULL_REQUEST_TEMPLATE.md + ..\README.md = ..\README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AC9AE37A-3059-4FDB-9A5C-363AD86F2EEF}" + ProjectSection(SolutionItems) = preProject + ..\.build\build.ps1 = ..\.build\build.ps1 + ..\.build\docfx.json = ..\.build\docfx.json + ..\.build\setup.ps1 = ..\.build\setup.ps1 + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Mono", "Titanium.Web.Proxy\Titanium.Web.Proxy.Mono.csproj", "{5985EBC2-75E8-4555-B715-B2302D879F9B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples.Basic.Mono", "..\examples\Titanium.Web.Proxy.Examples.Basic\Titanium.Web.Proxy.Examples.Basic.Mono.csproj", "{9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Debug|x64.ActiveCfg = Debug|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Debug|x64.Build.0 = Debug|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Release|Any CPU.Build.0 = Release|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Release|x64.ActiveCfg = Release|Any CPU + {5985EBC2-75E8-4555-B715-B2302D879F9B}.Release|x64.Build.0 = Release|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Debug|x64.ActiveCfg = Debug|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Debug|x64.Build.0 = Debug|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Release|Any CPU.Build.0 = Release|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Release|x64.ActiveCfg = Release|Any CPU + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9B5FA6A0-8D7C-46AD-B4F5-3AF6E2720C09} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 + SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A} + EndGlobalSection +EndGlobal diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj new file mode 100644 index 000000000..b19879f31 --- /dev/null +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj @@ -0,0 +1,48 @@ + + + + net45 + Titanium.Web.Proxy + false + True + StrongNameKey.snk + True + 7.1 + AnyCPU;x64 + + + + + + + + + + + + + + + + True + True + + + True + True + + + True + True + + + True + True + + + True + True + + + + \ No newline at end of file From c6b908be21300edc076a57d969c561aa1869fed9 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 22:41:17 -0400 Subject: [PATCH 31/40] update IDE --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5424f7c45..69fb7eb69 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,12 @@ Supports Development enviroment used to work and build this project is described below for each platforms. #### Windows +* Visual Studio Code as IDE for .NET core * Visual Studio 2017 as IDE for .NET framework/.NET core -* Visual Studio Code as IDE for .NET framework/.NET core #### Mac OS -* Visual Studio 2017 as IDE for Mono/.NET core * Visual Studio Code as IDE for .NET core +* Visual Studio 2017 as IDE for Mono/.NET core #### Linux * Visual Studio Code as IDE for .NET core From 51124e82bd2cd76589f3ad790c7deeb8f2748e1b Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 3 Sep 2018 23:43:26 -0400 Subject: [PATCH 32/40] mono fix --- .../Titanium.Web.Proxy.Examples.Basic.Mono.csproj | 2 +- src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj index 88075afe5..bef8de10e 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.Mono.csproj @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj index b19879f31..6c1200d98 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.Mono.csproj @@ -17,7 +17,6 @@ - From 871985c079cbd697fd9e01e238ef8b72387a5b85 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 4 Sep 2018 00:21:33 -0400 Subject: [PATCH 33/40] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 69fb7eb69..e699d5ad8 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ Supports * .Net Framework 4.5 or above ### Development Environment -Development enviroment used to work and build this project is described below for each platforms. #### Windows * Visual Studio Code as IDE for .NET core From a861f38f42db532f2e4acbcb99fefbebeb4ea9ba Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 4 Sep 2018 10:03:58 -0400 Subject: [PATCH 34/40] release build --- .vscode/launch.json | 13 ++++++++++++- .vscode/settings.json | 6 ++++-- .vscode/tasks.json | 13 ++++++++++++- omnisharp.json | 3 ++- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index cd3c24d6f..20840235b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,18 @@ "cwd": "${workspaceRoot}", "stopAtEntry": false, "console": "integratedTerminal", - "preLaunchTask": "build-basic-example-netcore" + "preLaunchTask": "build-basic-example-netcore-debug" + }, + { + "name": "NetCore|Release|Basic Example", + "type": "coreclr", + "request": "launch", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Release/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", + "args": [], + "cwd": "${workspaceRoot}", + "stopAtEntry": false, + "console": "integratedTerminal", + "preLaunchTask": "build-basic-example-netcore-release" } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 329486332..b52a44941 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,8 @@ "**/Titanium.Web.Proxy.Examples.Wpf/" : true, "**/*.Basic.csproj/": true, "**/*.Docs.csproj/": true, - "**/*.Proxy.csproj/": true + "**/*.Proxy.csproj/": true, + "**/*.Proxy.csproj" : true }, "search.exclude": { "**/.build": true, @@ -30,6 +31,7 @@ "**/Titanium.Web.Proxy.Examples.Wpf/" : true, "**/*.Basic.csproj/": true, "**/*.Docs.csproj/": true, - "**/*.Proxy.csproj/": true + "**/*.Proxy.csproj/": true, + "**/*.Proxy.csproj" : true } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 48fec60eb..e6ade8240 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,7 +2,7 @@ "version": "2.0.0", "tasks": [ { - "label": "build-basic-example-netcore", + "label": "build-basic-example-netcore-debug", "type": "process", "command": "dotnet", "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj"], @@ -11,6 +11,17 @@ "kind": "build", "isDefault": true } + }, + { + "label": "build-basic-example-netcore-release", + "type": "process", + "command": "dotnet", + "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj", "-c", "Release"], + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } } ] } \ No newline at end of file diff --git a/omnisharp.json b/omnisharp.json index de8d40bba..382ef5dbd 100644 --- a/omnisharp.json +++ b/omnisharp.json @@ -5,7 +5,8 @@ "**/tests/", "**/Titanium.Web.Proxy.Examples.Wpf/", "**/*.Basic.csproj", - "**/*.Proxy.csproj" + "**/*.Proxy.csproj", + "**/*.Mono.csproj" ] } } \ No newline at end of file From 3f9663e7b7c3e70ec2fc549e21cec3a55f229033 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 4 Sep 2018 10:05:44 -0400 Subject: [PATCH 35/40] rm default --- .vscode/tasks.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e6ade8240..e561614db 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -17,11 +17,7 @@ "type": "process", "command": "dotnet", "args": ["build","${workspaceFolder}/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj", "-c", "Release"], - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } + "problemMatcher": "$msCompile" } ] } \ No newline at end of file From 33123c8e854e9ea23110b3f3330ba49ad5134092 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 4 Sep 2018 14:34:19 -0400 Subject: [PATCH 36/40] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e699d5ad8..3a25dab1d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Supports * .Net Standard 2.0 or above * .Net Framework 4.5 or above -### Development Environment +### Development environment #### Windows * Visual Studio Code as IDE for .NET core From f151c9952f23708045069707e5a445a6ad32603f Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Tue, 4 Sep 2018 18:29:39 -0400 Subject: [PATCH 37/40] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a25dab1d..c89652828 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Supports #### Mac OS * Visual Studio Code as IDE for .NET core -* Visual Studio 2017 as IDE for Mono/.NET core +* Visual Studio 2017 as IDE for Mono #### Linux * Visual Studio Code as IDE for .NET core From b6bdf04639a5a9b99bb923c8c4666bbda6fa5d32 Mon Sep 17 00:00:00 2001 From: Jehonathan Thomas Date: Fri, 21 Sep 2018 16:20:25 -0400 Subject: [PATCH 38/40] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c89652828..ed17da133 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Install by [nuget](https://www.nuget.org/packages/Titanium.Web.Proxy) For beta releases on [beta branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/beta) - Install-Package Titanium.Web.Proxy + Install-Package Titanium.Web.Proxy -Pre For stable releases on [stable branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/stable) From ebc25f50097ff93c22672486b4ce3469b7243d01 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Sat, 22 Sep 2018 08:36:10 -0400 Subject: [PATCH 39/40] optional prefetch --- .../ProxyTestController.cs | 1 - .../ExplicitClientHandler.cs | 17 ++++++++------ src/Titanium.Web.Proxy/ProxyServer.cs | 22 ++++++++++++++----- .../TransparentClientHandler.cs | 17 ++++++++------ 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index dfdfd243e..ec3077823 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -24,7 +24,6 @@ public class ProxyTestController public ProxyTestController() { proxyServer = new ProxyServer(); - proxyServer.EnableConnectionPool = true; // generate root certificate without storing it in file system //proxyServer.CertificateManager.CreateRootCertificate(false); diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index 4f4261bcb..ed1040169 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -152,11 +152,14 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, SslStream sslStream = null; - //don't pass cancellation token here - //it could cause floating server connections when client exits - prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, - isConnect: true, applicationProtocols: null, noCache: false, - cancellationToken: CancellationToken.None); + if (EnableTcpServerConnectionPrefetch) + { + //don't pass cancellation token here + //it could cause floating server connections when client exits + prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, + isConnect: true, applicationProtocols: null, noCache: false, + cancellationToken: CancellationToken.None); + } try { @@ -204,10 +207,10 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, decryptSsl = false; } - if(!decryptSsl) + if (!decryptSsl) { await tcpConnectionFactory.Release(prefetchConnectionTask, true); - prefetchConnectionTask = null; + prefetchConnectionTask = null; } } diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index b83aeec47..567c4908d 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -161,9 +161,19 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, /// /// Should we enable experimental server connection pool? - /// Defaults to disable. + /// Defaults to true. /// - public bool EnableConnectionPool { get; set; } + public bool EnableConnectionPool { get; set; } = true; + + /// + /// Should we enable tcp server connection prefetching? + /// When enabled, as soon as we receive a client connection we concurrently initiate + /// corresponding server connection process using CONNECT hostname or SNI hostname on a separate task so that after parsing client request + /// we will have the server connection immediately ready or in the process of getting ready. + /// If a server connection is available in cache then this prefetch task will immediatly return with the available connection from cache. + /// Defaults to true. + /// + public bool EnableTcpServerConnectionPrefetch { get; set; } = true; /// /// Buffer size in bytes used throughout this proxy. @@ -186,14 +196,14 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, public int MaxCachedConnections { get; set; } = 2; /// - /// Number of seconds to linger when Tcp connection is in TIME_WAIT state. - /// Default value is 30. + /// Number of seconds to linger when Tcp connection is in TIME_WAIT state. + /// Default value is 30. /// public int TcpTimeWaitSeconds { get; set; } = 30; /// - /// Should we reuse client/server tcp sockets. - /// Default is true (disabled for linux/macOS due to bug in .Net core). + /// Should we reuse client/server tcp sockets. + /// Default is true (disabled for linux/macOS due to bug in .Net core). /// public bool ReuseSocket { get; set; } = true; diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index 92d865552..2efda0321 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -63,13 +63,16 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn if (endPoint.DecryptSsl && args.DecryptSsl) { - //don't pass cancellation token here - //it could cause floating server connections when client exits - prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, - httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false, - proxyServer: this, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy, - noCache: false, cancellationToken: CancellationToken.None); - + if(EnableTcpServerConnectionPrefetch) + { + //don't pass cancellation token here + //it could cause floating server connections when client exits + prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, + httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false, + proxyServer: this, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy, + noCache: false, cancellationToken: CancellationToken.None); + } + SslStream sslStream = null; //do client authentication using fake certificate From 4d00181ed0d2478238bf4ba3c05e9c989a6f4e82 Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Sat, 22 Sep 2018 12:39:00 +0000 Subject: [PATCH 40/40] API documentation update by build server --- ...xy.EventArguments.AsyncEventHandler-1.html | 2 +- ...uments.BeforeSslAuthenticateEventArgs.html | 2 +- ...guments.CertificateSelectionEventArgs.html | 2 +- ...uments.CertificateValidationEventArgs.html | 2 +- ...nts.MultipartRequestPartSentEventArgs.html | 2 +- ...Proxy.EventArguments.SessionEventArgs.html | 2 +- ...y.EventArguments.SessionEventArgsBase.html | 2 +- ...guments.TunnelConnectSessionEventArgs.html | 2 +- .../Titanium.Web.Proxy.EventArguments.html | 2 +- .../Titanium.Web.Proxy.ExceptionHandler.html | 2 +- ...roxy.Exceptions.BodyNotFoundException.html | 2 +- ...xceptions.ProxyAuthorizationException.html | 2 +- ...m.Web.Proxy.Exceptions.ProxyException.html | 2 +- ...b.Proxy.Exceptions.ProxyHttpException.html | 2 +- docs/api/Titanium.Web.Proxy.Exceptions.html | 2 +- .../Titanium.Web.Proxy.Helpers.RunTime.html | 2 +- docs/api/Titanium.Web.Proxy.Helpers.html | 2 +- ...itanium.Web.Proxy.Http.ConnectRequest.html | 2 +- ...tanium.Web.Proxy.Http.ConnectResponse.html | 2 +- ...anium.Web.Proxy.Http.HeaderCollection.html | 2 +- ...Titanium.Web.Proxy.Http.HttpWebClient.html | 2 +- .../Titanium.Web.Proxy.Http.KnownHeaders.html | 2 +- docs/api/Titanium.Web.Proxy.Http.Request.html | 2 +- ...um.Web.Proxy.Http.RequestResponseBase.html | 2 +- .../api/Titanium.Web.Proxy.Http.Response.html | 2 +- ....Proxy.Http.Responses.GenericResponse.html | 2 +- ...m.Web.Proxy.Http.Responses.OkResponse.html | 2 +- ...Proxy.Http.Responses.RedirectResponse.html | 2 +- .../Titanium.Web.Proxy.Http.Responses.html | 2 +- docs/api/Titanium.Web.Proxy.Http.html | 2 +- ...eb.Proxy.Models.ExplicitProxyEndPoint.html | 2 +- ...tanium.Web.Proxy.Models.ExternalProxy.html | 2 +- .../Titanium.Web.Proxy.Models.HttpHeader.html | 2 +- ...tanium.Web.Proxy.Models.ProxyEndPoint.html | 2 +- ...Proxy.Models.TransparentProxyEndPoint.html | 2 +- docs/api/Titanium.Web.Proxy.Models.html | 2 +- ...m.Web.Proxy.Network.CertificateEngine.html | 2 +- ....Web.Proxy.Network.CertificateManager.html | 2 +- docs/api/Titanium.Web.Proxy.Network.html | 2 +- docs/api/Titanium.Web.Proxy.ProxyServer.html | 35 +++++++++++++++++-- docs/api/Titanium.Web.Proxy.html | 2 +- docs/index.json | 2 +- docs/xrefmap.yml | 13 +++++++ 43 files changed, 87 insertions(+), 43 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html b/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html index a2bab66f9..c1dcd81f5 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html index 855d1e692..9d9f1ff6c 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html index 2d68bb8a4..0142a762c 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html index 7f4d6ba27..398b5a22f 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html index 1ce04ed84..087617766 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html index 942253ce2..37fc288fc 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html index dc6ef6f11..5f8fdd2f8 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html index 901a2be9b..d9bfeb87d 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.html b/docs/api/Titanium.Web.Proxy.EventArguments.html index 1dd02f117..0cbc01c73 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.ExceptionHandler.html b/docs/api/Titanium.Web.Proxy.ExceptionHandler.html index 1c5152cfd..df496faa5 100644 --- a/docs/api/Titanium.Web.Proxy.ExceptionHandler.html +++ b/docs/api/Titanium.Web.Proxy.ExceptionHandler.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html b/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html index 04bc0c4bf..9b837513d 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html index f4062b3c7..f8aa8ced5 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html index 75a6fb9cd..b76309410 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html index a1b16ff50..cb79e0f4d 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Exceptions.html b/docs/api/Titanium.Web.Proxy.Exceptions.html index 345784637..c578540ed 100644 --- a/docs/api/Titanium.Web.Proxy.Exceptions.html +++ b/docs/api/Titanium.Web.Proxy.Exceptions.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html b/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html index 40379c3a4..60916ec0d 100644 --- a/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html +++ b/docs/api/Titanium.Web.Proxy.Helpers.RunTime.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Helpers.html b/docs/api/Titanium.Web.Proxy.Helpers.html index e4d4a6d70..be01be7ee 100644 --- a/docs/api/Titanium.Web.Proxy.Helpers.html +++ b/docs/api/Titanium.Web.Proxy.Helpers.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html b/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html index e0a45ed92..158fe4978 100644 --- a/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html +++ b/docs/api/Titanium.Web.Proxy.Http.ConnectRequest.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html b/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html index 9bb0aa8e2..63e9d9d21 100644 --- a/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.ConnectResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html b/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html index b7f1d3e98..d615e87ee 100644 --- a/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html +++ b/docs/api/Titanium.Web.Proxy.Http.HeaderCollection.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html b/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html index 027c52388..88f31d580 100644 --- a/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html +++ b/docs/api/Titanium.Web.Proxy.Http.HttpWebClient.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html b/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html index cd013c1a1..1848bee9e 100644 --- a/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html +++ b/docs/api/Titanium.Web.Proxy.Http.KnownHeaders.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Request.html b/docs/api/Titanium.Web.Proxy.Http.Request.html index 904349249..7c169bad8 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Request.html +++ b/docs/api/Titanium.Web.Proxy.Http.Request.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html b/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html index 0921a7e85..4c45a4fe7 100644 --- a/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html +++ b/docs/api/Titanium.Web.Proxy.Http.RequestResponseBase.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Response.html b/docs/api/Titanium.Web.Proxy.Http.Response.html index 0a58d6871..5a789d502 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Response.html +++ b/docs/api/Titanium.Web.Proxy.Http.Response.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html index fd401c31d..3a24c85a0 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html index 21fdfa876..841700ad9 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.OkResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html b/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html index 233d77f97..31dbf166b 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.Responses.html b/docs/api/Titanium.Web.Proxy.Http.Responses.html index f94bec476..1cfc9f06e 100644 --- a/docs/api/Titanium.Web.Proxy.Http.Responses.html +++ b/docs/api/Titanium.Web.Proxy.Http.Responses.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Http.html b/docs/api/Titanium.Web.Proxy.Http.html index 56ffec05d..6c023dc6f 100644 --- a/docs/api/Titanium.Web.Proxy.Http.html +++ b/docs/api/Titanium.Web.Proxy.Http.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html index 402ac1598..7fc3b6e6e 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html b/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html index d7edcacc1..9b973be18 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html +++ b/docs/api/Titanium.Web.Proxy.Models.ExternalProxy.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html b/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html index 20b8ecb71..79b3b9a98 100644 --- a/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html +++ b/docs/api/Titanium.Web.Proxy.Models.HttpHeader.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html index 0c5f2c7e7..9a6376d69 100644 --- a/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.ProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html b/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html index 86e5af103..00c236443 100644 --- a/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html +++ b/docs/api/Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Models.html b/docs/api/Titanium.Web.Proxy.Models.html index 91962da07..a94e7625a 100644 --- a/docs/api/Titanium.Web.Proxy.Models.html +++ b/docs/api/Titanium.Web.Proxy.Models.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html b/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html index ea9d80e34..4958346a3 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateEngine.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html index 81f497b9e..1d21b311b 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.Network.html b/docs/api/Titanium.Web.Proxy.Network.html index d81b62e16..7bf3d2f01 100644 --- a/docs/api/Titanium.Web.Proxy.Network.html +++ b/docs/api/Titanium.Web.Proxy.Network.html @@ -10,7 +10,7 @@ - + diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index 1c1704c1a..7b921a904 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -10,7 +10,7 @@ - + @@ -423,7 +423,7 @@
    Property Value

    EnableConnectionPool

    Should we enable experimental server connection pool? -Defaults to disable.

    +Defaults to true.

    Declaration
    @@ -447,6 +447,37 @@
    Property Value
    + +

    EnableTcpServerConnectionPrefetch

    +

    Should we enable tcp server connection prefetching? +When enabled, as soon as we receive a client connection we concurrently initiate +corresponding server connection process using CONNECT hostname or SNI hostname on a separate task so that after parsing client request +we will have the server connection immediately ready or in the process of getting ready. +If a server connection is available in cache then this prefetch task will immediatly return with the available connection from cache. +Defaults to true.

    +
    +
    +
    Declaration
    +
    +
    public bool EnableTcpServerConnectionPrefetch { get; set; }
    +
    +
    Property Value
    + + + + + + + + + + + + + +
    TypeDescription
    Boolean
    + +

    EnableWinAuth

    Enable disable Windows Authentication (NTLM/Kerberos). diff --git a/docs/api/Titanium.Web.Proxy.html b/docs/api/Titanium.Web.Proxy.html index edcd6ca93..e075cb232 100644 --- a/docs/api/Titanium.Web.Proxy.html +++ b/docs/api/Titanium.Web.Proxy.html @@ -10,7 +10,7 @@ - + diff --git a/docs/index.json b/docs/index.json index 081247232..cb0102390 100644 --- a/docs/index.json +++ b/docs/index.json @@ -202,6 +202,6 @@ "api/Titanium.Web.Proxy.ProxyServer.html": { "href": "api/Titanium.Web.Proxy.ProxyServer.html", "title": "Class ProxyServer | Titanium Web Proxy", - "keywords": "Class ProxyServer This class is the backbone of proxy. One can create as many instances as needed. However care should be taken to avoid using the same listening ports across multiple instances. Inheritance Object ProxyServer Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy Assembly : Titanium.Web.Proxy.dll Syntax public class ProxyServer : IDisposable Constructors ProxyServer(Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? ProxyServer(String, String, Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description String rootCertificateName Name of the root certificate. String rootCertificateIssuerName Name of the root certificate issuer. Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? Properties BufferPool The buffer pool used throughout this proxy instance. Set custom implementations by implementing this interface. By default this uses DefaultBufferPool implementation available in StreamExtended library package. Declaration public IBufferPool BufferPool { get; set; } Property Value Type Description StreamExtended.IBufferPool BufferSize Buffer size in bytes used throughout this proxy. Default value is 8192 bytes. Declaration public int BufferSize { get; set; } Property Value Type Description Int32 CertificateManager Manages certificates used by this proxy. Declaration public CertificateManager CertificateManager { get; } Property Value Type Description CertificateManager CheckCertificateRevocation Should we check for certificare revocation during SSL authentication to servers Note: If enabled can reduce performance. Defaults to false. Declaration public X509RevocationMode CheckCertificateRevocation { get; set; } Property Value Type Description X509RevocationMode ClientConnectionCount Total number of active client connections. Declaration public int ClientConnectionCount { get; } Property Value Type Description Int32 ConnectionTimeOutSeconds Seconds client/server connection are to be kept alive when waiting for read/write to complete. This will also determine the pool eviction time when connection pool is enabled. Default value is 60 seconds. Declaration public int ConnectionTimeOutSeconds { get; set; } Property Value Type Description Int32 Enable100ContinueBehaviour Does this proxy uses the HTTP protocol 100 continue behaviour strictly? Broken 100 contunue implementations on server/client may cause problems if enabled. Defaults to false. Declaration public bool Enable100ContinueBehaviour { get; set; } Property Value Type Description Boolean EnableConnectionPool Should we enable experimental server connection pool? Defaults to disable. Declaration public bool EnableConnectionPool { get; set; } Property Value Type Description Boolean EnableWinAuth Enable disable Windows Authentication (NTLM/Kerberos). Note: NTLM/Kerberos will always send local credentials of current user running the proxy process. This is because a man in middle attack with Windows domain authentication is not currently supported. Defaults to false. Declaration public bool EnableWinAuth { get; set; } Property Value Type Description Boolean ExceptionFunc Callback for error events in this proxy instance. Declaration public ExceptionHandler ExceptionFunc { get; set; } Property Value Type Description ExceptionHandler ForwardToUpstreamGateway Gets or sets a value indicating whether requests will be chained to upstream gateway. Defaults to false. Declaration public bool ForwardToUpstreamGateway { get; set; } Property Value Type Description Boolean GetCustomUpStreamProxyFunc A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. User should return the ExternalProxy object with valid credentials. Declaration public Func> GetCustomUpStreamProxyFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , Task < ExternalProxy >> MaxCachedConnections Maximum number of concurrent connections per remote host in cache. Only valid when connection pooling is enabled. Default value is 2. Declaration public int MaxCachedConnections { get; set; } Property Value Type Description Int32 ProxyAuthenticationRealm Realm used during Proxy Basic Authentication. Declaration public string ProxyAuthenticationRealm { get; set; } Property Value Type Description String ProxyAuthenticationSchemes A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. Works in relation with ProxySchemeAuthenticateFunc. Declaration public IEnumerable ProxyAuthenticationSchemes { get; set; } Property Value Type Description IEnumerable < String > ProxyBasicAuthenticateFunc A callback to authenticate proxy clients via basic authentication. Parameters are username and password as provided by client. Should return true for successful authentication. Declaration public Func> ProxyBasicAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < Boolean >> ProxyEndPoints A list of IpAddress and port this proxy is listening to. Declaration public List ProxyEndPoints { get; set; } Property Value Type Description List < ProxyEndPoint > ProxyRunning Is the proxy currently running? Declaration public bool ProxyRunning { get; } Property Value Type Description Boolean ProxySchemeAuthenticateFunc A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. Parameters are current working session, schemeType, and token as provided by a calling client. Should return success for successful authentication, continuation if the package requests, or failure. Declaration public Func> ProxySchemeAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < ProxyAuthenticationContext >> ReuseSocket Should we reuse client/server tcp sockets. Default is true (disabled for linux/macOS due to bug in .Net core). Declaration public bool ReuseSocket { get; set; } Property Value Type Description Boolean ServerConnectionCount Total number of active server connections. Declaration public int ServerConnectionCount { get; } Property Value Type Description Int32 SupportedSslProtocols List of supported Ssl versions. Declaration public SslProtocols SupportedSslProtocols { get; set; } Property Value Type Description SslProtocols TcpTimeWaitSeconds Number of seconds to linger when Tcp connection is in TIME_WAIT state. Default value is 30. Declaration public int TcpTimeWaitSeconds { get; set; } Property Value Type Description Int32 UpStreamEndPoint Local adapter/NIC endpoint where proxy makes request via. Defaults via any IP addresses of this machine. Declaration public IPEndPoint UpStreamEndPoint { get; set; } Property Value Type Description IPEndPoint UpStreamHttpProxy External proxy used for Http requests. Declaration public ExternalProxy UpStreamHttpProxy { get; set; } Property Value Type Description ExternalProxy UpStreamHttpsProxy External proxy used for Https requests. Declaration public ExternalProxy UpStreamHttpsProxy { get; set; } Property Value Type Description ExternalProxy Methods AddEndPoint(ProxyEndPoint) Add a proxy end point. Declaration public void AddEndPoint(ProxyEndPoint endPoint) Parameters Type Name Description ProxyEndPoint endPoint The proxy endpoint. DisableAllSystemProxies() Clear all proxy settings for current machine. Declaration public void DisableAllSystemProxies() DisableSystemHttpProxy() Clear HTTP proxy settings of current machine. Declaration public void DisableSystemHttpProxy() DisableSystemHttpsProxy() Clear HTTPS proxy settings of current machine. Declaration public void DisableSystemHttpsProxy() DisableSystemProxy(ProxyProtocolType) Clear the specified proxy setting for current machine. Declaration public void DisableSystemProxy(ProxyProtocolType protocolType) Parameters Type Name Description ProxyProtocolType protocolType Dispose() Dispose the Proxy instance. Declaration public void Dispose() RemoveEndPoint(ProxyEndPoint) Remove a proxy end point. Will throw error if the end point does'nt exist. Declaration public void RemoveEndPoint(ProxyEndPoint endPoint) Parameters Type Name Description ProxyEndPoint endPoint The existing endpoint to remove. SetAsSystemHttpProxy(ExplicitProxyEndPoint) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. SetAsSystemHttpsProxy(ExplicitProxyEndPoint) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. ProxyProtocolType protocolType The proxy protocol type. Start() Start this proxy server instance. Declaration public void Start() Stop() Stop this proxy server instance. Declaration public void Stop() Events AfterResponse Intercept after response event from server. Declaration public event AsyncEventHandler AfterResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeRequest Intercept request event to server. Declaration public event AsyncEventHandler BeforeRequest Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeResponse Intercept response event from server. Declaration public event AsyncEventHandler BeforeResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > ClientCertificateSelectionCallback Event to override client certificate selection during mutual SSL authentication. Declaration public event AsyncEventHandler ClientCertificateSelectionCallback Event Type Type Description AsyncEventHandler < CertificateSelectionEventArgs > ClientConnectionCountChanged Event occurs when client connection count changed. Declaration public event EventHandler ClientConnectionCountChanged Event Type Type Description EventHandler OnClientConnectionCreate Customize TcpClient used for client connection upon create. Declaration public event AsyncEventHandler OnClientConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > OnServerConnectionCreate Customize TcpClient used for server connection upon create. Declaration public event AsyncEventHandler OnServerConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > ServerCertificateValidationCallback Event to override the default verification logic of remote SSL certificate received during authentication. Declaration public event AsyncEventHandler ServerCertificateValidationCallback Event Type Type Description AsyncEventHandler < CertificateValidationEventArgs > ServerConnectionCountChanged Event occurs when server connection count changed. Declaration public event EventHandler ServerConnectionCountChanged Event Type Type Description EventHandler Implements System.IDisposable" + "keywords": "Class ProxyServer This class is the backbone of proxy. One can create as many instances as needed. However care should be taken to avoid using the same listening ports across multiple instances. Inheritance Object ProxyServer Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy Assembly : Titanium.Web.Proxy.dll Syntax public class ProxyServer : IDisposable Constructors ProxyServer(Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? ProxyServer(String, String, Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description String rootCertificateName Name of the root certificate. String rootCertificateIssuerName Name of the root certificate issuer. Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? Properties BufferPool The buffer pool used throughout this proxy instance. Set custom implementations by implementing this interface. By default this uses DefaultBufferPool implementation available in StreamExtended library package. Declaration public IBufferPool BufferPool { get; set; } Property Value Type Description StreamExtended.IBufferPool BufferSize Buffer size in bytes used throughout this proxy. Default value is 8192 bytes. Declaration public int BufferSize { get; set; } Property Value Type Description Int32 CertificateManager Manages certificates used by this proxy. Declaration public CertificateManager CertificateManager { get; } Property Value Type Description CertificateManager CheckCertificateRevocation Should we check for certificare revocation during SSL authentication to servers Note: If enabled can reduce performance. Defaults to false. Declaration public X509RevocationMode CheckCertificateRevocation { get; set; } Property Value Type Description X509RevocationMode ClientConnectionCount Total number of active client connections. Declaration public int ClientConnectionCount { get; } Property Value Type Description Int32 ConnectionTimeOutSeconds Seconds client/server connection are to be kept alive when waiting for read/write to complete. This will also determine the pool eviction time when connection pool is enabled. Default value is 60 seconds. Declaration public int ConnectionTimeOutSeconds { get; set; } Property Value Type Description Int32 Enable100ContinueBehaviour Does this proxy uses the HTTP protocol 100 continue behaviour strictly? Broken 100 contunue implementations on server/client may cause problems if enabled. Defaults to false. Declaration public bool Enable100ContinueBehaviour { get; set; } Property Value Type Description Boolean EnableConnectionPool Should we enable experimental server connection pool? Defaults to true. Declaration public bool EnableConnectionPool { get; set; } Property Value Type Description Boolean EnableTcpServerConnectionPrefetch Should we enable tcp server connection prefetching? When enabled, as soon as we receive a client connection we concurrently initiate corresponding server connection process using CONNECT hostname or SNI hostname on a separate task so that after parsing client request we will have the server connection immediately ready or in the process of getting ready. If a server connection is available in cache then this prefetch task will immediatly return with the available connection from cache. Defaults to true. Declaration public bool EnableTcpServerConnectionPrefetch { get; set; } Property Value Type Description Boolean EnableWinAuth Enable disable Windows Authentication (NTLM/Kerberos). Note: NTLM/Kerberos will always send local credentials of current user running the proxy process. This is because a man in middle attack with Windows domain authentication is not currently supported. Defaults to false. Declaration public bool EnableWinAuth { get; set; } Property Value Type Description Boolean ExceptionFunc Callback for error events in this proxy instance. Declaration public ExceptionHandler ExceptionFunc { get; set; } Property Value Type Description ExceptionHandler ForwardToUpstreamGateway Gets or sets a value indicating whether requests will be chained to upstream gateway. Defaults to false. Declaration public bool ForwardToUpstreamGateway { get; set; } Property Value Type Description Boolean GetCustomUpStreamProxyFunc A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. User should return the ExternalProxy object with valid credentials. Declaration public Func> GetCustomUpStreamProxyFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , Task < ExternalProxy >> MaxCachedConnections Maximum number of concurrent connections per remote host in cache. Only valid when connection pooling is enabled. Default value is 2. Declaration public int MaxCachedConnections { get; set; } Property Value Type Description Int32 ProxyAuthenticationRealm Realm used during Proxy Basic Authentication. Declaration public string ProxyAuthenticationRealm { get; set; } Property Value Type Description String ProxyAuthenticationSchemes A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. Works in relation with ProxySchemeAuthenticateFunc. Declaration public IEnumerable ProxyAuthenticationSchemes { get; set; } Property Value Type Description IEnumerable < String > ProxyBasicAuthenticateFunc A callback to authenticate proxy clients via basic authentication. Parameters are username and password as provided by client. Should return true for successful authentication. Declaration public Func> ProxyBasicAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < Boolean >> ProxyEndPoints A list of IpAddress and port this proxy is listening to. Declaration public List ProxyEndPoints { get; set; } Property Value Type Description List < ProxyEndPoint > ProxyRunning Is the proxy currently running? Declaration public bool ProxyRunning { get; } Property Value Type Description Boolean ProxySchemeAuthenticateFunc A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. Parameters are current working session, schemeType, and token as provided by a calling client. Should return success for successful authentication, continuation if the package requests, or failure. Declaration public Func> ProxySchemeAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < ProxyAuthenticationContext >> ReuseSocket Should we reuse client/server tcp sockets. Default is true (disabled for linux/macOS due to bug in .Net core). Declaration public bool ReuseSocket { get; set; } Property Value Type Description Boolean ServerConnectionCount Total number of active server connections. Declaration public int ServerConnectionCount { get; } Property Value Type Description Int32 SupportedSslProtocols List of supported Ssl versions. Declaration public SslProtocols SupportedSslProtocols { get; set; } Property Value Type Description SslProtocols TcpTimeWaitSeconds Number of seconds to linger when Tcp connection is in TIME_WAIT state. Default value is 30. Declaration public int TcpTimeWaitSeconds { get; set; } Property Value Type Description Int32 UpStreamEndPoint Local adapter/NIC endpoint where proxy makes request via. Defaults via any IP addresses of this machine. Declaration public IPEndPoint UpStreamEndPoint { get; set; } Property Value Type Description IPEndPoint UpStreamHttpProxy External proxy used for Http requests. Declaration public ExternalProxy UpStreamHttpProxy { get; set; } Property Value Type Description ExternalProxy UpStreamHttpsProxy External proxy used for Https requests. Declaration public ExternalProxy UpStreamHttpsProxy { get; set; } Property Value Type Description ExternalProxy Methods AddEndPoint(ProxyEndPoint) Add a proxy end point. Declaration public void AddEndPoint(ProxyEndPoint endPoint) Parameters Type Name Description ProxyEndPoint endPoint The proxy endpoint. DisableAllSystemProxies() Clear all proxy settings for current machine. Declaration public void DisableAllSystemProxies() DisableSystemHttpProxy() Clear HTTP proxy settings of current machine. Declaration public void DisableSystemHttpProxy() DisableSystemHttpsProxy() Clear HTTPS proxy settings of current machine. Declaration public void DisableSystemHttpsProxy() DisableSystemProxy(ProxyProtocolType) Clear the specified proxy setting for current machine. Declaration public void DisableSystemProxy(ProxyProtocolType protocolType) Parameters Type Name Description ProxyProtocolType protocolType Dispose() Dispose the Proxy instance. Declaration public void Dispose() RemoveEndPoint(ProxyEndPoint) Remove a proxy end point. Will throw error if the end point does'nt exist. Declaration public void RemoveEndPoint(ProxyEndPoint endPoint) Parameters Type Name Description ProxyEndPoint endPoint The existing endpoint to remove. SetAsSystemHttpProxy(ExplicitProxyEndPoint) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. SetAsSystemHttpsProxy(ExplicitProxyEndPoint) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType) Set the given explicit end point as the default proxy server for current machine. Declaration public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) Parameters Type Name Description ExplicitProxyEndPoint endPoint The explicit endpoint. ProxyProtocolType protocolType The proxy protocol type. Start() Start this proxy server instance. Declaration public void Start() Stop() Stop this proxy server instance. Declaration public void Stop() Events AfterResponse Intercept after response event from server. Declaration public event AsyncEventHandler AfterResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeRequest Intercept request event to server. Declaration public event AsyncEventHandler BeforeRequest Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeResponse Intercept response event from server. Declaration public event AsyncEventHandler BeforeResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > ClientCertificateSelectionCallback Event to override client certificate selection during mutual SSL authentication. Declaration public event AsyncEventHandler ClientCertificateSelectionCallback Event Type Type Description AsyncEventHandler < CertificateSelectionEventArgs > ClientConnectionCountChanged Event occurs when client connection count changed. Declaration public event EventHandler ClientConnectionCountChanged Event Type Type Description EventHandler OnClientConnectionCreate Customize TcpClient used for client connection upon create. Declaration public event AsyncEventHandler OnClientConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > OnServerConnectionCreate Customize TcpClient used for server connection upon create. Declaration public event AsyncEventHandler OnServerConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > ServerCertificateValidationCallback Event to override the default verification logic of remote SSL certificate received during authentication. Declaration public event AsyncEventHandler ServerCertificateValidationCallback Event Type Type Description AsyncEventHandler < CertificateValidationEventArgs > ServerConnectionCountChanged Event occurs when server connection count changed. Declaration public event EventHandler ServerConnectionCountChanged Event Type Type Description EventHandler Implements System.IDisposable" } } diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index 68da43ef4..8edb4db78 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -2879,6 +2879,19 @@ references: isSpec: "True" fullName: Titanium.Web.Proxy.ProxyServer.EnableConnectionPool nameWithType: ProxyServer.EnableConnectionPool +- uid: Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch + name: EnableTcpServerConnectionPrefetch + href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableTcpServerConnectionPrefetch + commentId: P:Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch + fullName: Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch + nameWithType: ProxyServer.EnableTcpServerConnectionPrefetch +- uid: Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch* + name: EnableTcpServerConnectionPrefetch + href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableTcpServerConnectionPrefetch_ + commentId: Overload:Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch + isSpec: "True" + fullName: Titanium.Web.Proxy.ProxyServer.EnableTcpServerConnectionPrefetch + nameWithType: ProxyServer.EnableTcpServerConnectionPrefetch - uid: Titanium.Web.Proxy.ProxyServer.EnableWinAuth name: EnableWinAuth href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableWinAuth