diff --git a/appveyor.yml b/appveyor.yml
index 37c305e1f..6189bfc71 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -27,7 +27,7 @@ cache: .build\cleanup-cache.txt
# to run your custom scripts instead of automatic MSBuild
build_script:
- - cmd: build.bat Package
+ - cmd: build.bat
assembly_info:
patch: true
@@ -39,6 +39,8 @@ assembly_info:
# to disable automatic tests
test: on
+test_script:
+ - cmd: test.bat
# skip building commits that add tags (such as release tag)
skip_tags: true
diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html
index 3a80595f6..51a3e3206 100644
--- a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html
+++ b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html
@@ -552,6 +552,54 @@
Returns
+
+ |
+ Improve this Doc
+
+
+ View Source
+
+
+ CreateServerCertificate(String)
+ Creates a server certificate signed by the root certificate.
+
+
+ Declaration
+
+
public Task<X509Certificate2> CreateServerCertificate(string certificateName)
+
+ Parameters
+
+
+
+ | Type |
+ Name |
+ Description |
+
+
+
+
+ | String |
+ certificateName |
+ |
+
+
+
+ Returns
+
|
Improve this Doc
diff --git a/docs/index.json b/docs/index.json
index 688199fdc..59769f0a5 100644
--- a/docs/index.json
+++ b/docs/index.json
@@ -267,7 +267,7 @@
"api/Titanium.Web.Proxy.Network.CertificateManager.html": {
"href": "api/Titanium.Web.Proxy.Network.CertificateManager.html",
"title": "Class CertificateManager | Titanium Web Proxy",
- "keywords": "Class CertificateManager A class to manage SSL certificates used by this proxy server. Inheritance Object CertificateManager 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.Network Assembly : Titanium.Web.Proxy.dll Syntax public sealed class CertificateManager : IDisposable Properties | Improve this Doc View Source CertificateCacheTimeOutMinutes Minutes certificates should be kept in cache when not used. Declaration public int CertificateCacheTimeOutMinutes { get; set; } Property Value Type Description Int32 | Improve this Doc View Source CertificateEngine Select Certificate Engine. Optionally set to BouncyCastle. Mono only support BouncyCastle and it is the default. Declaration public CertificateEngine CertificateEngine { get; set; } Property Value Type Description CertificateEngine | Improve this Doc View Source CertificateStorage The fake certificate cache storage. The default cache storage implementation saves certificates in folder \"crts\" (will be created in proxy dll directory). Implement ICertificateCache interface and assign concrete class here to customize. Declaration public ICertificateCache CertificateStorage { get; set; } Property Value Type Description ICertificateCache | Improve this Doc View Source OverwritePfxFile Overwrite Root certificate file. true : replace an existing .pfx file if password is incorrect or if RootCertificate = null. Declaration public bool OverwritePfxFile { get; set; } Property Value Type Description Boolean | Improve this Doc View Source PfxFilePath Name(path) of the Root certificate file. Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory) Declaration public string PfxFilePath { get; set; } Property Value Type Description String | Improve this Doc View Source PfxPassword Password of the Root certificate file. Set a password for the .pfx file Declaration public string PfxPassword { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificate The root certificate. Declaration public X509Certificate2 RootCertificate { get; set; } Property Value Type Description X509Certificate2 | Improve this Doc View Source RootCertificateIssuerName Name of the root certificate issuer. (This is valid only when RootCertificate property is not set.) Declaration public string RootCertificateIssuerName { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificateName Name of the root certificate. (This is valid only when RootCertificate property is not set.) If no certificate is provided then a default Root Certificate will be created and used. The provided root certificate will be stored in proxy exe directory with the private key. Root certificate file will be named as \"rootCert.pfx\". Declaration public string RootCertificateName { get; set; } Property Value Type Description String | Improve this Doc View Source SaveFakeCertificates Save all fake certificates using CertificateStorage . for can load the certificate and not make new certificate every time. Declaration public bool SaveFakeCertificates { get; set; } Property Value Type Description Boolean | Improve this Doc View Source StorageFlag Adjust behaviour when certificates are saved to filesystem. Declaration public X509KeyStorageFlags StorageFlag { get; set; } Property Value Type Description X509KeyStorageFlags Methods | Improve this Doc View Source ClearRootCertificate() Clear the root certificate and cache. Declaration public void ClearRootCertificate() | Improve this Doc View Source CreateRootCertificate(Boolean) Attempts to create a RootCertificate. Declaration public bool CreateRootCertificate(bool persistToFile = true) Parameters Type Name Description Boolean persistToFile if set to true try to load/save the certificate from rootCert.pfx. Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source Dispose() Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Declaration public void Dispose() | Improve this Doc View Source EnsureRootCertificate() Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on initial setup from proxy constructor for user/machine trust. Declaration public void EnsureRootCertificate() | Improve this Doc View Source EnsureRootCertificate(Boolean, Boolean, Boolean) Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on provided parameters. Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true. Declaration public void EnsureRootCertificate(bool userTrustRootCertificate, bool machineTrustRootCertificate, 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? | Improve this Doc View Source IsRootCertificateMachineTrusted() Determines whether the root certificate is machine trusted. Declaration public bool IsRootCertificateMachineTrusted() Returns Type Description Boolean | Improve this Doc View Source IsRootCertificateUserTrusted() Determines whether the root certificate is trusted. Declaration public bool IsRootCertificateUserTrusted() Returns Type Description Boolean | Improve this Doc View Source LoadRootCertificate() Loads root certificate from current executing assembly location with expected name rootCert.pfx. Declaration public X509Certificate2 LoadRootCertificate() Returns Type Description X509Certificate2 | Improve this Doc View Source LoadRootCertificate(String, String, Boolean, X509KeyStorageFlags) Manually load a Root certificate file from give path (.pfx file). Declaration public bool LoadRootCertificate(string pfxFilePath, string password, bool overwritePfXFile = true, X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable) Parameters Type Name Description String pfxFilePath Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory). String password Set a password for the .pfx file. Boolean overwritePfXFile true : replace an existing .pfx file if password is incorrect or if RootCertificate==null. X509KeyStorageFlags storageFlag Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source RemoveTrustedRootCertificate(Boolean) Removes the trusted certificates from user store, optionally also from machine store. To remove from machine store elevated permissions are required (will fail silently otherwise). Declaration public void RemoveTrustedRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Should also remove from machine store? | Improve this Doc View Source RemoveTrustedRootCertificateAsAdmin(Boolean) Removes the trusted certificates from user store, optionally also from machine store Declaration public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean Should also remove from machine store? | Improve this Doc View Source TrustRootCertificate(Boolean) Trusts the root certificate in user store, optionally also in machine store. Machine trust would require elevated permissions (will silently fail otherwise). Declaration public void TrustRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted | Improve this Doc View Source TrustRootCertificateAsAdmin(Boolean) Puts the certificate to the user store, optionally also to machine store. Prompts with UAC if elevated permissions are required. Works only on Windows. Declaration public bool TrustRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean True if success. Implements System.IDisposable"
+ "keywords": "Class CertificateManager A class to manage SSL certificates used by this proxy server. Inheritance Object CertificateManager 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.Network Assembly : Titanium.Web.Proxy.dll Syntax public sealed class CertificateManager : IDisposable Properties | Improve this Doc View Source CertificateCacheTimeOutMinutes Minutes certificates should be kept in cache when not used. Declaration public int CertificateCacheTimeOutMinutes { get; set; } Property Value Type Description Int32 | Improve this Doc View Source CertificateEngine Select Certificate Engine. Optionally set to BouncyCastle. Mono only support BouncyCastle and it is the default. Declaration public CertificateEngine CertificateEngine { get; set; } Property Value Type Description CertificateEngine | Improve this Doc View Source CertificateStorage The fake certificate cache storage. The default cache storage implementation saves certificates in folder \"crts\" (will be created in proxy dll directory). Implement ICertificateCache interface and assign concrete class here to customize. Declaration public ICertificateCache CertificateStorage { get; set; } Property Value Type Description ICertificateCache | Improve this Doc View Source OverwritePfxFile Overwrite Root certificate file. true : replace an existing .pfx file if password is incorrect or if RootCertificate = null. Declaration public bool OverwritePfxFile { get; set; } Property Value Type Description Boolean | Improve this Doc View Source PfxFilePath Name(path) of the Root certificate file. Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory) Declaration public string PfxFilePath { get; set; } Property Value Type Description String | Improve this Doc View Source PfxPassword Password of the Root certificate file. Set a password for the .pfx file Declaration public string PfxPassword { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificate The root certificate. Declaration public X509Certificate2 RootCertificate { get; set; } Property Value Type Description X509Certificate2 | Improve this Doc View Source RootCertificateIssuerName Name of the root certificate issuer. (This is valid only when RootCertificate property is not set.) Declaration public string RootCertificateIssuerName { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificateName Name of the root certificate. (This is valid only when RootCertificate property is not set.) If no certificate is provided then a default Root Certificate will be created and used. The provided root certificate will be stored in proxy exe directory with the private key. Root certificate file will be named as \"rootCert.pfx\". Declaration public string RootCertificateName { get; set; } Property Value Type Description String | Improve this Doc View Source SaveFakeCertificates Save all fake certificates using CertificateStorage . for can load the certificate and not make new certificate every time. Declaration public bool SaveFakeCertificates { get; set; } Property Value Type Description Boolean | Improve this Doc View Source StorageFlag Adjust behaviour when certificates are saved to filesystem. Declaration public X509KeyStorageFlags StorageFlag { get; set; } Property Value Type Description X509KeyStorageFlags Methods | Improve this Doc View Source ClearRootCertificate() Clear the root certificate and cache. Declaration public void ClearRootCertificate() | Improve this Doc View Source CreateRootCertificate(Boolean) Attempts to create a RootCertificate. Declaration public bool CreateRootCertificate(bool persistToFile = true) Parameters Type Name Description Boolean persistToFile if set to true try to load/save the certificate from rootCert.pfx. Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source CreateServerCertificate(String) Creates a server certificate signed by the root certificate. Declaration public Task CreateServerCertificate(string certificateName) Parameters Type Name Description String certificateName Returns Type Description Task < X509Certificate2 > | Improve this Doc View Source Dispose() Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Declaration public void Dispose() | Improve this Doc View Source EnsureRootCertificate() Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on initial setup from proxy constructor for user/machine trust. Declaration public void EnsureRootCertificate() | Improve this Doc View Source EnsureRootCertificate(Boolean, Boolean, Boolean) Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on provided parameters. Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true. Declaration public void EnsureRootCertificate(bool userTrustRootCertificate, bool machineTrustRootCertificate, 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? | Improve this Doc View Source IsRootCertificateMachineTrusted() Determines whether the root certificate is machine trusted. Declaration public bool IsRootCertificateMachineTrusted() Returns Type Description Boolean | Improve this Doc View Source IsRootCertificateUserTrusted() Determines whether the root certificate is trusted. Declaration public bool IsRootCertificateUserTrusted() Returns Type Description Boolean | Improve this Doc View Source LoadRootCertificate() Loads root certificate from current executing assembly location with expected name rootCert.pfx. Declaration public X509Certificate2 LoadRootCertificate() Returns Type Description X509Certificate2 | Improve this Doc View Source LoadRootCertificate(String, String, Boolean, X509KeyStorageFlags) Manually load a Root certificate file from give path (.pfx file). Declaration public bool LoadRootCertificate(string pfxFilePath, string password, bool overwritePfXFile = true, X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable) Parameters Type Name Description String pfxFilePath Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory). String password Set a password for the .pfx file. Boolean overwritePfXFile true : replace an existing .pfx file if password is incorrect or if RootCertificate==null. X509KeyStorageFlags storageFlag Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source RemoveTrustedRootCertificate(Boolean) Removes the trusted certificates from user store, optionally also from machine store. To remove from machine store elevated permissions are required (will fail silently otherwise). Declaration public void RemoveTrustedRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Should also remove from machine store? | Improve this Doc View Source RemoveTrustedRootCertificateAsAdmin(Boolean) Removes the trusted certificates from user store, optionally also from machine store Declaration public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean Should also remove from machine store? | Improve this Doc View Source TrustRootCertificate(Boolean) Trusts the root certificate in user store, optionally also in machine store. Machine trust would require elevated permissions (will silently fail otherwise). Declaration public void TrustRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted | Improve this Doc View Source TrustRootCertificateAsAdmin(Boolean) Puts the certificate to the user store, optionally also to machine store. Prompts with UAC if elevated permissions are required. Works only on Windows. Declaration public bool TrustRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean True if success. Implements System.IDisposable"
},
"api/Titanium.Web.Proxy.Network.html": {
"href": "api/Titanium.Web.Proxy.Network.html",
diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml
index ecda8f2ac..17b310164 100644
--- a/docs/xrefmap.yml
+++ b/docs/xrefmap.yml
@@ -3035,6 +3035,19 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateRootCertificate
nameWithType: CertificateManager.CreateRootCertificate
+- uid: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String)
+ name: CreateServerCertificate(String)
+ href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_System_String_
+ commentId: M:Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String)
+ fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String)
+ nameWithType: CertificateManager.CreateServerCertificate(String)
+- uid: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate*
+ name: CreateServerCertificate
+ href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_
+ commentId: Overload:Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate
+ isSpec: "True"
+ fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate
+ nameWithType: CertificateManager.CreateServerCertificate
- uid: Titanium.Web.Proxy.Network.CertificateManager.Dispose
name: Dispose()
href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_Dispose
diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln
index 34eb45ecc..982c03221 100644
--- a/src/Titanium.Web.Proxy.sln
+++ b/src/Titanium.Web.Proxy.sln
@@ -25,12 +25,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "Titan
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}"
-EndProject
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.Wpf", "..\examples\Titanium.Web.Proxy.Examples.Wpf\Titanium.Web.Proxy.Examples.Wpf.csproj", "{4406CE17-9A39-4F28-8363-6169A4F799C1}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.IntegrationTests", "..\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{1D053D72-DCB4-4517-ACDD-D35ADC186950}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -49,20 +49,12 @@ Global
{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}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.Build.0 = Debug|Any CPU
{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
+ {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.ActiveCfg = Release|Any CPU
+ {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.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}.Debug|x64.ActiveCfg = Debug|x64
@@ -79,18 +71,26 @@ Global
{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
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|x64.Build.0 = Debug|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.ActiveCfg = Release|Any CPU
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
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}
+ {1D053D72-DCB4-4517-ACDD-D35ADC186950} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A}
+ EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
EndGlobalSection
EndGlobal
diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
index 3191fa2db..0fa047686 100644
--- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
@@ -168,7 +168,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
string certName = HttpHelper.GetWildCardDomainName(connectHostname);
var certificate = endPoint.GenericCertificate ??
- await CertificateManager.CreateCertificateAsync(certName);
+ await CertificateManager.CreateServerCertificate(certName);
// Successfully managed to authenticate the client using the fake certificate
var options = new SslServerAuthenticationOptions();
diff --git a/src/Titanium.Web.Proxy/Network/CertificateManager.cs b/src/Titanium.Web.Proxy/Network/CertificateManager.cs
index cf0aee98c..d7b2164c9 100644
--- a/src/Titanium.Web.Proxy/Network/CertificateManager.cs
+++ b/src/Titanium.Web.Proxy/Network/CertificateManager.cs
@@ -432,11 +432,11 @@ internal X509Certificate2 CreateCertificate(string certificateName, bool isRootC
}
///
- /// Create an SSL certificate async
+ /// Creates a server certificate signed by the root certificate.
///
///
///
- internal async Task CreateCertificateAsync(string certificateName)
+ public async Task CreateServerCertificate(string certificateName)
{
// check in cache first
if (cachedCertificates.TryGetValue(certificateName, out var cached))
diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs
index f5077f5cd..8d5ffcfdb 100644
--- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs
+++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs
@@ -34,10 +34,6 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
- Task prefetchConnectionTask = null;
- bool closeServerConnection = false;
- bool calledRequestHandler = false;
-
try
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
@@ -63,16 +59,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn
if (endPoint.DecryptSsl && args.DecryptSsl)
{
- 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, session: null, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy,
- noCache: false, cancellationToken: CancellationToken.None);
- }
-
+
SslStream sslStream = null;
//do client authentication using fake certificate
@@ -82,7 +69,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn
string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
var certificate = endPoint.GenericCertificate ??
- await CertificateManager.CreateCertificateAsync(certName);
+ await CertificateManager.CreateServerCertificate(certName);
// Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
@@ -140,39 +127,29 @@ await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize,
return;
}
}
- calledRequestHandler = true;
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
- cancellationTokenSource, isHttps ? httpsHostName : null, null, prefetchConnectionTask);
+ cancellationTokenSource, isHttps ? httpsHostName : null, null, null);
}
catch (ProxyException e)
{
- closeServerConnection = true;
onException(clientStream, e);
}
catch (IOException e)
{
- closeServerConnection = true;
onException(clientStream, new Exception("Connection was aborted", e));
}
catch (SocketException e)
{
- closeServerConnection = true;
onException(clientStream, new Exception("Could not connect", e));
}
catch (Exception e)
{
- closeServerConnection = true;
onException(clientStream, new Exception("Error occured in whilst handling the client", e));
}
finally
{
- if (!calledRequestHandler)
- {
- await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
- }
-
clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested)
diff --git a/test.bat b/test.bat
new file mode 100644
index 000000000..4e688b0a5
--- /dev/null
+++ b/test.bat
@@ -0,0 +1,5 @@
+@echo off
+
+dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj" -c %CONFIGURATION%
+dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj" -c %CONFIGURATION%
+exit /B %errorlevel%
\ No newline at end of file
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs
new file mode 100644
index 000000000..928867604
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Net;
+using System.Net.Http;
+
+namespace Titanium.Web.Proxy.IntegrationTests.Helpers
+{
+ public static class TestHelper
+ {
+ public static HttpClient GetHttpClient(int localProxyPort)
+ {
+ var proxy = new TestProxy($"http://localhost:{localProxyPort}");
+
+ var handler = new HttpClientHandler
+ {
+ Proxy = proxy,
+ UseProxy = true
+ };
+
+ return new HttpClient(handler);
+ }
+
+ public static HttpClient GetHttpClient()
+ {
+ return new HttpClient(new HttpClientHandler());
+ }
+
+ public class TestProxy : IWebProxy
+ {
+ public Uri ProxyUri { get; set; }
+ public ICredentials Credentials { get; set; }
+
+ public TestProxy(string proxyUri)
+ : this(new Uri(proxyUri))
+ {
+ }
+
+ public TestProxy(Uri proxyUri)
+ {
+ this.ProxyUri = proxyUri;
+ }
+
+ public Uri GetProxy(Uri destination)
+ {
+ return this.ProxyUri;
+ }
+
+ public bool IsBypassed(Uri host)
+ {
+ return false;
+ }
+
+ }
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
new file mode 100644
index 000000000..cb1621bef
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Titanium.Web.Proxy.IntegrationTests
+{
+ [TestClass]
+ public class HttpsTests
+ {
+ [TestMethod]
+ public async Task Can_Handle_Https_Request()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetProxy();
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.PostAsync(new Uri(server.ListeningHttpsUrl),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs
index 7a4ccfcd3..574909124 100644
--- a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs
@@ -2,9 +2,8 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Titanium.Web.Proxy.EventArguments;
-using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.IntegrationTests
{
@@ -12,61 +11,177 @@ namespace Titanium.Web.Proxy.IntegrationTests
public class InterceptionTests
{
[TestMethod]
- public async Task Can_Intercept_Post_Requests()
+ public async Task Can_Intercept_Get_Requests()
{
- string testUrl = "http://interceptthis.com";
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
- using (var proxy = new ProxyTestController())
+ var proxy = testSuite.GetProxy();
+ proxy.BeforeRequest += async (sender, e) =>
{
- using (var client = TestHelper.CreateHttpClient(testUrl, proxy.ListeningPort))
+ if (e.HttpClient.Request.Url.Contains("localhost"))
{
- var response = await client.PostAsync(new Uri(testUrl), new StringContent("hello!"));
+ e.Ok("TitaniumWebProxy-Stopped!!");
+ return;
+ }
- Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.GetAsync(new Uri(server.ListeningHttpUrl));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
- var body = await response.Content.ReadAsStringAsync();
- Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
- }
- }
}
- private class ProxyTestController : IDisposable
+ [TestMethod]
+ public async Task Can_Intercept_Post_Requests()
{
- private readonly ProxyServer proxyServer;
- public int ListeningPort => proxyServer.ProxyEndPoints[0].Port;
+ var testSuite = new TestSuite();
- public ProxyTestController()
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
{
- proxyServer = new ProxyServer();
- var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 0, true);
- proxyServer.AddEndPoint(explicitEndPoint);
- proxyServer.BeforeRequest += OnRequest;
- proxyServer.Start();
- }
-
- public async Task OnRequest(object sender, SessionEventArgs e)
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetProxy();
+ proxy.BeforeRequest += async (sender, e) =>
{
- if (e.HttpClient.Request.Url.Contains("interceptthis.com"))
+ if (e.HttpClient.Request.Url.Contains("localhost"))
{
- if (e.HttpClient.Request.HasBody)
- {
- var body = await e.GetRequestBodyAsString();
- }
+ e.Ok("TitaniumWebProxy-Stopped!!");
+ return;
+ }
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.PostAsync(new Uri(server.ListeningHttpUrl),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
+
+ }
+
+ [TestMethod]
+ public async Task Can_Intercept_Put_Requests()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ if (e.HttpClient.Request.Url.Contains("localhost"))
+ {
e.Ok("TitaniumWebProxy-Stopped!!");
return;
}
await Task.FromResult(0);
- }
+ };
+
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.PutAsync(new Uri(server.ListeningHttpUrl),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
- public void Dispose()
+ }
+
+
+ [TestMethod]
+ public async Task Can_Intercept_Patch_Requests()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetProxy();
+ proxy.BeforeRequest += async (sender, e) =>
{
- proxyServer.BeforeRequest -= OnRequest;
- proxyServer.Stop();
- proxyServer.Dispose();
- }
+ if (e.HttpClient.Request.Url.Contains("localhost"))
+ {
+ e.Ok("TitaniumWebProxy-Stopped!!");
+ return;
+ }
+
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.PatchAsync(new Uri(server.ListeningHttpUrl),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
+
}
+ [TestMethod]
+ public async Task Can_Intercept_Delete_Requests()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ if (e.HttpClient.Request.Url.Contains("localhost"))
+ {
+ e.Ok("TitaniumWebProxy-Stopped!!");
+ return;
+ }
+
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetClient(proxy);
+
+ var response = await client.DeleteAsync(new Uri(server.ListeningHttpUrl));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!"));
+
+ }
}
}
\ No newline at end of file
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs
new file mode 100644
index 000000000..a5cc804ce
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs
@@ -0,0 +1,39 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Titanium.Web.Proxy.IntegrationTests
+{
+ [TestClass]
+ public class NestedProxyTests
+ {
+ [TestMethod]
+ public async Task Smoke_Test_Nested_Proxy()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy1 = testSuite.GetProxy();
+ var proxy2 = testSuite.GetProxy(proxy1);
+
+ var client = testSuite.GetClient(proxy2);
+
+ var response = await client.PostAsync(new Uri(server.ListeningHttpsUrl),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs
deleted file mode 100644
index 0e5f845f1..000000000
--- a/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Titanium.Web.Proxy.IntegrationTests")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Titanium.Web.Proxy.IntegrationTests")]
-[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("32231301-b0fb-4f9e-98df-b3e8a88f4c16")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs
new file mode 100644
index 000000000..37a6fb6d9
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs
@@ -0,0 +1,130 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Titanium.Web.Proxy.IntegrationTests
+{
+ [TestClass]
+ public class ReverseProxyTests
+ {
+ [TestMethod]
+ public async Task Smoke_Test_Http_To_Http_Reverse_Proxy()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetReverseProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpUrl);
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetReverseProxyClient();
+
+ var response = await client.PostAsync(new Uri($"http://localhost:{proxy.ProxyEndPoints[0].Port}"),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ [TestMethod]
+ public async Task Smoke_Test_Https_To_Http_Reverse_Proxy()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetReverseProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpUrl);
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetReverseProxyClient();
+
+ var response = await client.PostAsync(new Uri($"https://localhost:{proxy.ProxyEndPoints[0].Port}"),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ [TestMethod]
+ public async Task Smoke_Test_Http_To_Https_Reverse_Proxy()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetReverseProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpsUrl);
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetReverseProxyClient();
+
+ var response = await client.PostAsync(new Uri($"http://localhost:{proxy.ProxyEndPoints[0].Port}"),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ [TestMethod]
+ public async Task Smoke_Test_Https_To_Https_Reverse_Proxy()
+ {
+ var testSuite = new TestSuite();
+
+ var server = testSuite.GetServer();
+ server.HandleRequest((context) =>
+ {
+ return context.Response.WriteAsync("I am server. I received your greetings.");
+ });
+
+ var proxy = testSuite.GetReverseProxy();
+ proxy.BeforeRequest += async (sender, e) =>
+ {
+ e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpsUrl);
+ await Task.FromResult(0);
+ };
+
+ var client = testSuite.GetReverseProxyClient();
+
+ var response = await client.PostAsync(new Uri($"https://localhost:{proxy.ProxyEndPoints[0].Port}"),
+ new StringContent("hello server. I am a client."));
+
+ Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+
+ Assert.AreEqual("I am server. I received your greetings.", body);
+ }
+
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs
new file mode 100644
index 000000000..ab868c15c
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using Titanium.Web.Proxy.EventArguments;
+using Titanium.Web.Proxy.Models;
+using Titanium.Web.Proxy.Network;
+
+namespace Titanium.Web.Proxy.IntegrationTests.Setup
+{
+ public class TestProxyServer : IDisposable
+ {
+ public ProxyServer ProxyServer { get; private set; }
+ public int ListeningPort => ProxyServer.ProxyEndPoints[0].Port;
+ public CertificateManager CertificateManager => ProxyServer.CertificateManager;
+
+ public TestProxyServer(bool isReverseProxy, ProxyServer upStreamProxy = null)
+ {
+ ProxyServer = new ProxyServer();
+ ProxyEndPoint explicitEndPoint = isReverseProxy ?
+ (ProxyEndPoint)new TransparentProxyEndPoint(IPAddress.Any, 0, true) :
+ new ExplicitProxyEndPoint(IPAddress.Any, 0, true);
+
+ ProxyServer.AddEndPoint(explicitEndPoint);
+
+ if (upStreamProxy != null)
+ {
+ ProxyServer.UpStreamHttpProxy = new ExternalProxy()
+ {
+ HostName = "localhost",
+ Port = upStreamProxy.ProxyEndPoints[0].Port
+ };
+
+ ProxyServer.UpStreamHttpsProxy = new ExternalProxy()
+ {
+ HostName = "localhost",
+ Port = upStreamProxy.ProxyEndPoints[0].Port
+ };
+ }
+
+ ProxyServer.Start();
+ }
+
+ public void Dispose()
+ {
+ ProxyServer.Stop();
+ ProxyServer.Dispose();
+ }
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
new file mode 100644
index 000000000..1f8dfeec7
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
@@ -0,0 +1,98 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http;
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using System.Linq;
+using System.Net;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Titanium.Web.Proxy.IntegrationTests.Setup
+{
+ //set up a kestrel test server
+ public class TestServer : IDisposable
+ {
+ public string ListeningHttpUrl => $"http://localhost:{HttpListeningPort}";
+ public string ListeningHttpsUrl => $"https://localhost:{HttpsListeningPort}";
+
+ public int HttpListeningPort { get; private set; }
+ public int HttpsListeningPort { get; private set; }
+
+ private IWebHost host;
+ public TestServer(X509Certificate2 serverCertificate)
+ {
+ var startUp = new Startup(() => requestHandler);
+
+ host = WebHost.CreateDefaultBuilder()
+ .ConfigureServices(s =>
+ {
+ s.AddSingleton(startUp);
+ })
+ .UseKestrel(options =>
+ {
+ options.Listen(IPAddress.Loopback, 0);
+ options.Listen(IPAddress.Loopback, 0, listenOptions =>
+ {
+ listenOptions.UseHttps(serverCertificate);
+ });
+ })
+ .Build();
+
+ host.Start();
+
+ var addresses = host.ServerFeatures
+ .Get()
+ .Addresses.ToArray();
+
+ string httpAddress = addresses[0];
+ HttpListeningPort = int.Parse(httpAddress.Split(':')[2]);
+
+ string httpsAddress = addresses[1];
+ HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]);
+ }
+
+ Func requestHandler = null;
+ public void HandleRequest(Func requestHandler)
+ {
+ this.requestHandler = requestHandler;
+ }
+
+ public void Dispose()
+ {
+ host.StopAsync().Wait();
+ host.Dispose();
+ }
+
+ private class Startup : IStartup
+ {
+ Func> requestHandler;
+ public Startup(Func> requestHandler)
+ {
+ this.requestHandler = requestHandler;
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.Run(context =>
+ {
+ if (requestHandler == null)
+ {
+ throw new Exception("Test server not configured to handle request.");
+ }
+
+ return requestHandler()(context);
+ });
+
+ }
+
+ public IServiceProvider ConfigureServices(IServiceCollection services)
+ {
+ return services.BuildServiceProvider();
+ }
+ }
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs
new file mode 100644
index 000000000..0c0b611ec
--- /dev/null
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using Titanium.Web.Proxy.IntegrationTests.Helpers;
+using Titanium.Web.Proxy.IntegrationTests.Setup;
+
+namespace Titanium.Web.Proxy.IntegrationTests
+{
+ public class TestSuite
+ {
+ private TestServer server;
+
+ public TestSuite()
+ {
+ var dummyProxy = new ProxyServer();
+ var serverCertificate = dummyProxy.CertificateManager.CreateServerCertificate("localhost").Result;
+ server = new TestServer(serverCertificate);
+ }
+
+ public TestServer GetServer()
+ {
+ return server;
+ }
+
+ public ProxyServer GetProxy(ProxyServer upStreamProxy = null)
+ {
+ if (upStreamProxy != null)
+ {
+ return new TestProxyServer(false, upStreamProxy).ProxyServer;
+ }
+
+ return new TestProxyServer(false).ProxyServer;
+ }
+
+ public ProxyServer GetReverseProxy(ProxyServer upStreamProxy = null)
+ {
+ if (upStreamProxy != null)
+ {
+ return new TestProxyServer(true, upStreamProxy).ProxyServer;
+ }
+
+ return new TestProxyServer(true).ProxyServer;
+ }
+
+ public HttpClient GetClient(ProxyServer proxyServer)
+ {
+ return TestHelper.GetHttpClient(proxyServer.ProxyEndPoints[0].Port);
+ }
+
+ public HttpClient GetReverseProxyClient()
+ {
+ return TestHelper.GetHttpClient();
+ }
+ }
+}
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs
deleted file mode 100644
index 56441b1bd..000000000
--- a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System;
-using System.Net;
-using System.Threading.Tasks;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Titanium.Web.Proxy.Models;
-
-namespace Titanium.Web.Proxy.IntegrationTests
-{
- [TestClass]
- public class SslTests
- {
- [TestMethod]
- public async Task TestSsl()
- {
- string testUrl = "https://google.com";
- using (var proxy = new ProxyTestController())
- {
- using (var client = TestHelper.CreateHttpClient(testUrl, proxy.ListeningPort))
- {
- var response = await client.GetAsync(new Uri(testUrl));
- Assert.IsNotNull(response);
- }
- }
- }
-
- private class ProxyTestController : IDisposable
- {
- private readonly ProxyServer proxyServer;
- public int ListeningPort => proxyServer.ProxyEndPoints[0].Port;
-
- public ProxyTestController()
- {
- proxyServer = new ProxyServer();
- var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 0, true);
- proxyServer.AddEndPoint(explicitEndPoint);
- proxyServer.Start();
- }
-
- public void Dispose()
- {
- proxyServer.Stop();
- proxyServer.Dispose();
- }
- }
- }
-}
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 05ffdca66..fadb82120 100644
--- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj
+++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj
@@ -1,117 +1,27 @@
-
-
+
+
- Debug
- AnyCPU
- {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}
- Library
- Properties
- Titanium.Web.Proxy.IntegrationTests
- Titanium.Web.Proxy.IntegrationTests
- v4.5.2
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 10.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- UnitTest
-
+ netcoreapp2.2
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
- true
- bin\x64\Debug\
- DEBUG;TRACE
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
- bin\x64\Release\
- TRACE
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+ PreserveNewest
+
+
-
- {91018b6d-a7a9-45be-9cb3-79cbb8b169a6}
- Titanium.Web.Proxy
-
+
+
+
+
+
+
+
+
-
- rootCert.pfx
- PreserveNewest
-
+
-
-
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs
deleted file mode 100644
index a763a1d11..000000000
--- a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Net;
-using System.Net.Http;
-
-namespace Titanium.Web.Proxy.IntegrationTests
-{
- public static class TestHelper
- {
- public static HttpClient CreateHttpClient(string url, int localProxyPort)
- {
- var handler = new HttpClientHandler
- {
- Proxy = new WebProxy($"http://localhost:{localProxyPort}", false),
- UseProxy = true
- };
-
- return new HttpClient(handler);
- }
- }
-}
diff --git a/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs b/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
index 15a464683..a97b5a3de 100644
--- a/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
+++ b/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs
@@ -45,10 +45,9 @@ public async Task Simple_BC_Create_Certificate_Test()
}
// uncomment this to compare WinCert maker performance with BC (BC takes more time for same test above)
- [TestMethod]
+ //[TestMethod]
public async Task Simple_Create_Win_Certificate_Test()
{
-
var tasks = new List();
var mgr = new CertificateManager(null, null, false, false, false, new Lazy(() => (e =>
diff --git a/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs
index 88cea1a29..f7f99ff11 100644
--- a/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs
+++ b/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs
@@ -4,11 +4,7 @@
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
-[assembly: AssemblyTitle("Titanium.Web.Proxy.UnitTests")]
[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Titanium.Web.Proxy.UnitTests")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -20,16 +16,3 @@
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b517e3d0-d03b-436f-ab03-34ba0d5321af")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
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 b89d06841..dff5cb58c 100644
--- a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
+++ b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
@@ -1,122 +1,23 @@
-
-
-
- Debug
- AnyCPU
- {B517E3D0-D03B-436F-AB03-34BA0D5321AF}
- Library
- Properties
- Titanium.Web.Proxy.UnitTests
- Titanium.Web.Proxy.UnitTests
- v4.5.2
- 512
- {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 10.0
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
- $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
- False
- UnitTest
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- true
-
+
+
+ net45
true
-
-
StrongNameKey.snk
-
- true
- bin\x64\Debug\
- DEBUG;TRACE
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
- bin\x64\Release\
- TRACE
- true
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
+
+
-
+
+
-
- {91018b6d-a7a9-45be-9cb3-79cbb8b169a6}
- Titanium.Web.Proxy
-
+
-
-
-
-
- False
-
-
- False
-
-
- False
-
-
- False
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+