Unverified Commit d3ad2f8b authored by justcoding121's avatar justcoding121 Committed by GitHub

Merge pull request #429 from justcoding121/master

Beta
parents 698084c6 ad5a5d3c
...@@ -205,4 +205,4 @@ FakesAssemblies/ ...@@ -205,4 +205,4 @@ FakesAssemblies/
*.opt *.opt
# Docfx # Docfx
docs/manifest.json docs/manifest.json
\ No newline at end of file
...@@ -9,10 +9,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -9,10 +9,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
public static void Main(string[] args) public static void Main(string[] args)
{ {
//fix console hang due to QuickEdit mode // fix console hang due to QuickEdit mode
ConsoleHelper.DisableQuickEditMode(); ConsoleHelper.DisableQuickEditMode();
//Start proxy controller // Start proxy controller
controller.StartProxy(); controller.StartProxy();
Console.WriteLine("Hit any key to exit.."); Console.WriteLine("Hit any key to exit..");
......
...@@ -18,26 +18,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -18,26 +18,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
private readonly ProxyServer proxyServer; private readonly ProxyServer proxyServer;
//keep track of request headers
private readonly IDictionary<Guid, HeaderCollection> requestHeaderHistory =
new ConcurrentDictionary<Guid, HeaderCollection>();
//keep track of response headers
private readonly IDictionary<Guid, HeaderCollection> responseHeaderHistory =
new ConcurrentDictionary<Guid, HeaderCollection>();
private ExplicitProxyEndPoint explicitEndPoint; private ExplicitProxyEndPoint explicitEndPoint;
//share requestBody outside handlers
//Using a dictionary is not a good idea since it can cause memory overflow
//ideally the data should be moved out of memory
//private readonly IDictionary<Guid, string> requestBodyHistory = new ConcurrentDictionary<Guid, string>();
public ProxyTestController() public ProxyTestController()
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//generate root certificate without storing it in file system // generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateRootCertificate(false); //proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate(); //proxyServer.CertificateManager.TrustRootCertificate();
...@@ -63,11 +50,12 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -63,11 +50,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
}; };
proxyServer.ForwardToUpstreamGateway = true; proxyServer.ForwardToUpstreamGateway = true;
proxyServer.CertificateManager.SaveFakeCertificates = true; proxyServer.CertificateManager.SaveFakeCertificates = true;
//optionally set the Certificate Engine
//Under Mono or Non-Windows runtimes only BouncyCastle will be supported // optionally set the Certificate Engine
// Under Mono or Non-Windows runtimes only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle; //proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
//optionally set the Root Certificate // optionally set the Root Certificate
//proxyServer.CertificateManager.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable); //proxyServer.CertificateManager.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
} }
...@@ -83,27 +71,26 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -83,27 +71,26 @@ namespace Titanium.Web.Proxy.Examples.Basic
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000); explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000);
//Fired when a CONNECT request is received // Fired when a CONNECT request is received
explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += OnBeforeTunnelConnectResponse; explicitEndPoint.BeforeTunnelConnectResponse += OnBeforeTunnelConnectResponse;
//An explicit endpoint is where the client knows about the existence of a proxy // An explicit endpoint is where the client knows about the existence of a proxy
//So client sends request in a proxy friendly manner // So client sends request in a proxy friendly manner
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
proxyServer.Start(); proxyServer.Start();
//Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy) // Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)
//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS // A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS
//to send data to this endPoint // to send data to this endPoint
//var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true) //var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true)
//{ //{
// //Generic Certificate hostname to use // // Generic Certificate hostname to use
// //When SNI is disabled by client // // When SNI is disabled by client
// GenericCertificateName = "google.com" // GenericCertificateName = "google.com"
//}; //};
//proxyServer.AddEndPoint(transparentEndPoint); //proxyServer.AddEndPoint(transparentEndPoint);
//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
...@@ -117,7 +104,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -117,7 +104,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
#endif #endif
{ {
//Only explicit proxies can be set as system proxy! // Only explicit proxies can be set as system proxy!
//proxyServer.SetAsSystemHttpProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
//proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp);
...@@ -135,8 +122,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -135,8 +122,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection; proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
proxyServer.Stop(); proxyServer.Stop();
//remove the generated certificates // remove the generated certificates
//proxyServer.CertificateManager.RemoveTrustedRootCertificates(); //proxyServer.CertificateManager.RemoveTrustedRootCertificates();
} }
...@@ -147,9 +134,9 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -147,9 +134,9 @@ namespace Titanium.Web.Proxy.Examples.Basic
if (hostname.Contains("dropbox.com")) if (hostname.Contains("dropbox.com"))
{ {
//Exclude Https addresses you don't want to proxy // Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning // Useful for clients that use certificate pinning
//for example dropbox.com // for example dropbox.com
e.DecryptSsl = false; e.DecryptSsl = false;
} }
} }
...@@ -158,14 +145,20 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -158,14 +145,20 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
} }
//intecept & cancel redirect or update requests // intecept & cancel redirect or update requests
private async Task OnRequest(object sender, SessionEventArgs e) private async Task OnRequest(object sender, SessionEventArgs e)
{ {
WriteToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount); WriteToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
WriteToConsole(e.WebSession.Request.Url); WriteToConsole(e.WebSession.Request.Url);
//read request headers // store it in the UserData property
requestHeaderHistory[e.Id] = e.WebSession.Request.Headers; // It can be a simple integer, Guid, or any type
//e.UserData = new CustomUserData()
//{
// RequestHeaders = e.WebSession.Request.Headers,
// RequestBody = e.WebSession.Request.HasBody ? e.WebSession.Request.Body:null,
// RequestBodyString = e.WebSession.Request.HasBody? e.WebSession.Request.BodyString:null
//};
////This sample shows how to get the multipart form data headers ////This sample shows how to get the multipart form data headers
//if (e.WebSession.Request.Host == "mail.yahoo.com" && e.WebSession.Request.IsMultipartFormData) //if (e.WebSession.Request.Host == "mail.yahoo.com" && e.WebSession.Request.IsMultipartFormData)
...@@ -173,23 +166,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -173,23 +166,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
// e.MultipartRequestPartSent += MultipartRequestPartSent; // e.MultipartRequestPartSent += MultipartRequestPartSent;
//} //}
//if (e.WebSession.Request.HasBody) // To cancel a request with a custom HTML content
//{ // Filter URL
// //Get/Set request body bytes
// var bodyBytes = await e.GetRequestBody();
// await e.SetRequestBody(bodyBytes);
// //Get/Set request body as string
// string bodyString = await e.GetRequestBodyAsString();
// await e.SetRequestBodyString(bodyString);
// //requestBodyHistory[e.Id] = bodyString;
//}
//To cancel a request with a custom HTML content
//Filter URL
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com")) //if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com"))
//{ //{
// e.Ok("<!DOCTYPE html>" + // e.Ok("<!DOCTYPE html>" +
// "<html><body><h1>" + // "<html><body><h1>" +
// "Website Blocked" + // "Website Blocked" +
...@@ -197,16 +177,16 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -197,16 +177,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
// "<p>Blocked by titanium web proxy.</p>" + // "<p>Blocked by titanium web proxy.</p>" +
// "</body>" + // "</body>" +
// "</html>"); // "</html>");
//} //}
////Redirect example ////Redirect example
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) //if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
//{ //{
// e.Redirect("https://www.paypal.com"); // e.Redirect("https://www.paypal.com");
//} //}
} }
//Modify response // Modify response
private void MultipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e) private void MultipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
{ {
var session = (SessionEventArgs)sender; var session = (SessionEventArgs)sender;
...@@ -221,21 +201,34 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -221,21 +201,34 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
WriteToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount); WriteToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
//if (requestBodyHistory.ContainsKey(e.Id)) string ext = System.IO.Path.GetExtension(e.WebSession.Request.RequestUri.AbsolutePath);
//{
// //access request body by looking up the shared dictionary using requestId
// var requestBody = requestBodyHistory[e.Id];
//}
////read response headers //access user data set in request to do something with it
//responseHeaderHistory[e.Id] = e.WebSession.Response.Headers; //var userData = e.WebSession.UserData as CustomUserData;
//if (ext == ".gif" || ext == ".png" || ext == ".jpg")
//{
// byte[] btBody = Encoding.UTF8.GetBytes("<!DOCTYPE html>" +
// "<html><body><h1>" +
// "Image is blocked" +
// "</h1>" +
// "<p>Blocked by Titanium</p>" +
// "</body>" +
// "</html>");
// var response = new OkResponse(btBody);
// response.HttpVersion = e.WebSession.Request.HttpVersion;
// e.Respond(response);
// e.TerminateServerConnection();
//}
//// print out process id of current session //// print out process id of current session
////WriteToConsole($"PID: {e.WebSession.ProcessId.Value}"); ////WriteToConsole($"PID: {e.WebSession.ProcessId.Value}");
////if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return; ////if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
//if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST") //if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
//{ //{
// if (e.WebSession.Response.StatusCode == (int)HttpStatusCode.OK) // if (e.WebSession.Response.StatusCode == (int)HttpStatusCode.OK)
// { // {
// if (e.WebSession.Response.ContentType != null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html")) // if (e.WebSession.Response.ContentType != null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))
...@@ -247,7 +240,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -247,7 +240,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
// await e.SetResponseBodyString(body); // await e.SetResponseBodyString(body);
// } // }
// } // }
//} //}
} }
/// <summary> /// <summary>
...@@ -257,7 +250,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -257,7 +250,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// <param name="e"></param> /// <param name="e"></param>
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors // set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == SslPolicyErrors.None) if (e.SslPolicyErrors == SslPolicyErrors.None)
{ {
e.IsValid = true; e.IsValid = true;
...@@ -273,7 +266,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -273,7 +266,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// <param name="e"></param> /// <param name="e"></param>
public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e) public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{ {
//set e.clientCertificate to override // set e.clientCertificate to override
return Task.FromResult(0); return Task.FromResult(0);
} }
...@@ -285,5 +278,16 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -285,5 +278,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
Console.WriteLine(message); Console.WriteLine(message);
} }
} }
///// <summary>
///// User data object as defined by user.
///// User data can be set to each SessionEventArgs.WebSession.UserData property
///// </summary>
//public class CustomUserData
//{
// public HeaderCollection RequestHeaders { get; set; }
// public byte[] RequestBody { get; set; }
// public string RequestBodyString { get; set; }
//}
} }
} }
...@@ -9,7 +9,6 @@ using System.Windows; ...@@ -9,7 +9,6 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="StreamExtended, Version=1.0.147.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.164.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.147-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\..\packages\StreamExtended.1.0.164\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="StreamExtended" version="1.0.147-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.164" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
...@@ -121,10 +121,6 @@ Sample request and response event handlers ...@@ -121,10 +121,6 @@ Sample request and response event handlers
```csharp ```csharp
//To access requestBody from OnResponse handler
private IDictionary<Guid, string> requestBodyHistory
= new ConcurrentDictionary<Guid, string>();
private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{ {
string hostname = e.WebSession.Request.RequestUri.Host; string hostname = e.WebSession.Request.RequestUri.Host;
...@@ -156,9 +152,9 @@ public async Task OnRequest(object sender, SessionEventArgs e) ...@@ -156,9 +152,9 @@ public async Task OnRequest(object sender, SessionEventArgs e)
string bodyString = await e.GetRequestBodyAsString(); string bodyString = await e.GetRequestBodyAsString();
await e.SetRequestBodyString(bodyString); await e.SetRequestBodyString(bodyString);
//store request Body/request headers etc with request Id as key //store request
//so that you can find it from response handler using request Id //so that you can find it from response handler
requestBodyHistory[e.Id] = bodyString; e.UserData = e.WebSession.Request;
} }
//To cancel a request with a custom HTML content //To cancel a request with a custom HTML content
...@@ -202,11 +198,12 @@ public async Task OnResponse(object sender, SessionEventArgs e) ...@@ -202,11 +198,12 @@ public async Task OnResponse(object sender, SessionEventArgs e)
} }
} }
//access request body/request headers etc by looking up using requestId if(e.UserData!=null)
if(requestBodyHistory.ContainsKey(e.Id))
{ {
var requestBody = requestBodyHistory[e.Id]; //access request from UserData property where we stored it in RequestHandler
var request = (Request)e.UserData;
} }
} }
/// Allows overriding default certificate validation logic /// Allows overriding default certificate validation logic
......
...@@ -17,8 +17,8 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -17,8 +17,8 @@ namespace Titanium.Web.Proxy.IntegrationTests
//disable this test until CI is prepared to handle //disable this test until CI is prepared to handle
public void TestSsl() public void TestSsl()
{ {
//expand this to stress test to find // expand this to stress test to find
//why in long run proxy becomes unresponsive as per issue #184 // why in long run proxy becomes unresponsive as per issue #184
string testUrl = "https://google.com"; string testUrl = "https://google.com";
int proxyPort = 8086; int proxyPort = 8086;
var proxy = new ProxyTestController(); var proxy = new ProxyTestController();
...@@ -62,8 +62,8 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -62,8 +62,8 @@ namespace Titanium.Web.Proxy.IntegrationTests
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, proxyPort, true); var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, proxyPort, true);
//An explicit endpoint is where the client knows about the existance of a proxy // An explicit endpoint is where the client knows about the existance of a proxy
//So client sends request in a proxy friendly manner // So client sends request in a proxy friendly manner
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
proxyServer.Start(); proxyServer.Start();
...@@ -84,14 +84,14 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -84,14 +84,14 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxyServer.Stop(); proxyServer.Stop();
} }
//intecept & cancel, redirect or update requests // intecept & cancel, redirect or update requests
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
Debug.WriteLine(e.WebSession.Request.Url); Debug.WriteLine(e.WebSession.Request.Url);
await Task.FromResult(0); await Task.FromResult(0);
} }
//Modify response // Modify response
public async Task OnResponse(object sender, SessionEventArgs e) public async Task OnResponse(object sender, SessionEventArgs e)
{ {
await Task.FromResult(0); await Task.FromResult(0);
...@@ -104,7 +104,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -104,7 +104,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
/// <param name="e"></param> /// <param name="e"></param>
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors // set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == SslPolicyErrors.None) if (e.SslPolicyErrors == SslPolicyErrors.None)
{ {
e.IsValid = true; e.IsValid = true;
...@@ -120,7 +120,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -120,7 +120,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
/// <param name="e"></param> /// <param name="e"></param>
public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e) public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{ {
//set e.clientCertificate to override // set e.clientCertificate to override
return Task.FromResult(0); return Task.FromResult(0);
} }
......
...@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
tasks.AddRange(hostNames.Select(host => Task.Run(() => tasks.AddRange(hostNames.Select(host => Task.Run(() =>
{ {
//get the connection // get the connection
var certificate = mgr.CreateCertificate(host, false); var certificate = mgr.CreateCertificate(host, false);
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
}))); })));
...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -44,7 +44,7 @@ namespace Titanium.Web.Proxy.UnitTests
mgr.StopClearIdleCertificates(); mgr.StopClearIdleCertificates();
} }
//uncomment this to compare WinCert maker performance with BC (BC takes more time for same test above) // 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() public async Task Simple_Create_Win_Certificate_Test()
{ {
...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -66,7 +66,7 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
tasks.AddRange(hostNames.Select(host => Task.Run(() => tasks.AddRange(hostNames.Select(host => Task.Run(() =>
{ {
//get the connection // get the connection
var certificate = mgr.CreateCertificate(host, false); var certificate = mgr.CreateCertificate(host, false);
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
}))); })));
......
using System; using System;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Network.WinAuth; using Titanium.Web.Proxy.Network.WinAuth;
namespace Titanium.Web.Proxy.UnitTests namespace Titanium.Web.Proxy.UnitTests
...@@ -10,7 +11,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -10,7 +11,7 @@ namespace Titanium.Web.Proxy.UnitTests
[TestMethod] [TestMethod]
public void Test_Acquire_Client_Token() public void Test_Acquire_Client_Token()
{ {
string token = WinAuthHandler.GetInitialAuthToken("mylocalserver.com", "NTLM", Guid.NewGuid()); string token = WinAuthHandler.GetInitialAuthToken("mylocalserver.com", "NTLM", new InternalDataStore());
Assert.IsTrue(token.Length > 1); Assert.IsTrue(token.Length > 1);
} }
} }
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) SslPolicyErrors sslPolicyErrors)
{ {
//if user callback is registered then do it // if user callback is registered then do it
if (ServerCertificateValidationCallback != null) if (ServerCertificateValidationCallback != null)
{ {
var args = new CertificateValidationEventArgs var args = new CertificateValidationEventArgs
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy
SslPolicyErrors = sslPolicyErrors SslPolicyErrors = sslPolicyErrors
}; };
//why is the sender null? // why is the sender null?
ServerCertificateValidationCallback.InvokeAsync(this, args, exceptionFunc).Wait(); ServerCertificateValidationCallback.InvokeAsync(this, args, exceptionFunc).Wait();
return args.IsValid; return args.IsValid;
} }
...@@ -39,8 +39,8 @@ namespace Titanium.Web.Proxy ...@@ -39,8 +39,8 @@ namespace Titanium.Web.Proxy
return true; return true;
} }
//By default // By default
//do not allow this client to communicate with unauthenticated servers. // do not allow this client to communicate with unauthenticated servers.
return false; return false;
} }
...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy ...@@ -77,7 +77,7 @@ namespace Titanium.Web.Proxy
clientCertificate = localCertificates[0]; clientCertificate = localCertificates[0];
} }
//If user call back is registered // If user call back is registered
if (ClientCertificateSelectionCallback != null) if (ClientCertificateSelectionCallback != null)
{ {
var args = new CertificateSelectionEventArgs var args = new CertificateSelectionEventArgs
...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy ...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy
ClientCertificate = clientCertificate ClientCertificate = clientCertificate
}; };
//why is the sender null? // why is the sender null?
ClientCertificateSelectionCallback.InvokeAsync(this, args, exceptionFunc).Wait(); ClientCertificateSelectionCallback.InvokeAsync(this, args, exceptionFunc).Wait();
return args.ClientCertificate; return args.ClientCertificate;
} }
......
using System; using System;
using System.IO;
using System.IO.Compression;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
...@@ -8,18 +10,14 @@ namespace Titanium.Web.Proxy.Compression ...@@ -8,18 +10,14 @@ namespace Titanium.Web.Proxy.Compression
/// </summary> /// </summary>
internal static class CompressionFactory internal static class CompressionFactory
{ {
//cache internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
private static readonly ICompression gzip = new GZipCompression();
private static readonly ICompression deflate = new DeflateCompression();
internal static ICompression GetCompression(string type)
{ {
switch (type) switch (type)
{ {
case KnownHeaders.ContentEncodingGzip: case KnownHeaders.ContentEncodingGzip:
return gzip; return new GZipStream(stream, CompressionMode.Compress, leaveOpen);
case KnownHeaders.ContentEncodingDeflate: case KnownHeaders.ContentEncodingDeflate:
return deflate; return new DeflateStream(stream, CompressionMode.Compress, leaveOpen);
default: default:
throw new Exception($"Unsupported compression mode: {type}"); throw new Exception($"Unsupported compression mode: {type}");
} }
......
using System; using System;
using System.IO;
using System.IO.Compression;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// A factory to generate the de-compression methods based on the type of compression /// A factory to generate the de-compression methods based on the type of compression
/// </summary> /// </summary>
internal class DecompressionFactory internal class DecompressionFactory
{ {
//cache internal static Stream Create(string type, Stream stream, bool leaveOpen = true)
private static readonly IDecompression gzip = new GZipDecompression();
private static readonly IDecompression deflate = new DeflateDecompression();
internal static IDecompression Create(string type)
{ {
switch (type) switch (type)
{ {
case KnownHeaders.ContentEncodingGzip: case KnownHeaders.ContentEncodingGzip:
return gzip; return new GZipStream(stream, CompressionMode.Decompress, leaveOpen);
case KnownHeaders.ContentEncodingDeflate: case KnownHeaders.ContentEncodingDeflate:
return deflate; return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen);
default: default:
throw new Exception($"Unsupported decompression mode: {type}"); throw new Exception($"Unsupported decompression mode: {type}");
} }
......
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Compression
{
/// <summary>
/// Concrete implementation of deflate compression
/// </summary>
internal class DeflateCompression : ICompression
{
public Stream GetStream(Stream stream)
{
return new DeflateStream(stream, CompressionMode.Compress, true);
}
}
}
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Compression
{
/// <summary>
/// concreate implementation of gzip compression
/// </summary>
internal class GZipCompression : ICompression
{
public Stream GetStream(Stream stream)
{
return new GZipStream(stream, CompressionMode.Compress, true);
}
}
}
using System.IO;
namespace Titanium.Web.Proxy.Compression
{
/// <summary>
/// An inteface for http compression
/// </summary>
internal interface ICompression
{
Stream GetStream(Stream stream);
}
}
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Decompression
{
/// <summary>
/// concrete implementation of deflate de-compression
/// </summary>
internal class DeflateDecompression : IDecompression
{
public Stream GetStream(Stream stream)
{
return new DeflateStream(stream, CompressionMode.Decompress, true);
}
}
}
using System.IO;
using System.IO.Compression;
namespace Titanium.Web.Proxy.Decompression
{
/// <summary>
/// concrete implementation of gzip de-compression
/// </summary>
internal class GZipDecompression : IDecompression
{
public Stream GetStream(Stream stream)
{
return new GZipStream(stream, CompressionMode.Decompress, true);
}
}
}
using System.IO;
namespace Titanium.Web.Proxy.Decompression
{
/// <summary>
/// An interface for decompression
/// </summary>
internal interface IDecompression
{
Stream GetStream(Stream stream);
}
}
using System;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// Wraps the data sent/received by a proxy server instance.
/// </summary>
public class DataEventArgs : EventArgs
{
internal DataEventArgs(byte[] buffer, int offset, int count)
{
Buffer = buffer;
Offset = offset;
Count = count;
}
/// <summary>
/// The buffer with data.
/// </summary>
public byte[] Buffer { get; }
/// <summary>
/// Offset in buffer from which valid data begins.
/// </summary>
public int Offset { get; }
/// <summary>
/// Length from offset in buffer with valid data.
/// </summary>
public int Count { get; }
}
}
...@@ -9,18 +9,16 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -9,18 +9,16 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
internal class LimitedStream : Stream internal class LimitedStream : Stream
{ {
private readonly CustomBinaryReader baseReader; private readonly ICustomStreamReader baseStream;
private readonly CustomBufferedStream baseStream;
private readonly bool isChunked; private readonly bool isChunked;
private long bytesRemaining; private long bytesRemaining;
private bool readChunkTrail; private bool readChunkTrail;
internal LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked, internal LimitedStream(ICustomStreamReader baseStream, bool isChunked,
long contentLength) long contentLength)
{ {
this.baseStream = baseStream; this.baseStream = baseStream;
this.baseReader = baseReader;
this.isChunked = isChunked; this.isChunked = isChunked;
bytesRemaining = isChunked bytesRemaining = isChunked
? 0 ? 0
...@@ -48,12 +46,12 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -48,12 +46,12 @@ namespace Titanium.Web.Proxy.EventArguments
if (readChunkTrail) if (readChunkTrail)
{ {
// read the chunk trail of the previous chunk // read the chunk trail of the previous chunk
string s = baseReader.ReadLineAsync().Result; string s = baseStream.ReadLineAsync().Result;
} }
readChunkTrail = true; readChunkTrail = true;
string chunkHead = baseReader.ReadLineAsync().Result; string chunkHead = baseStream.ReadLineAsync().Result;
int idx = chunkHead.IndexOf(";", StringComparison.Ordinal); int idx = chunkHead.IndexOf(";", StringComparison.Ordinal);
if (idx >= 0) if (idx >= 0)
{ {
...@@ -67,8 +65,8 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -67,8 +65,8 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
bytesRemaining = -1; bytesRemaining = -1;
//chunk trail // chunk trail
baseReader.ReadLineAsync().Wait(); baseStream.ReadLineAsync().Wait();
} }
} }
...@@ -127,7 +125,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -127,7 +125,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (bytesRemaining != -1) if (bytesRemaining != -1)
{ {
var buffer = BufferPool.GetBuffer(baseReader.Buffer.Length); var buffer = BufferPool.GetBuffer(baseStream.BufferSize);
try try
{ {
int res = await ReadAsync(buffer, 0, buffer.Length); int res = await ReadAsync(buffer, 0, buffer.Length);
......
...@@ -6,11 +6,12 @@ using System.Threading; ...@@ -6,11 +6,12 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Helpers; using StreamExtended.Helpers;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Decompression; using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses; using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
...@@ -68,16 +69,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -68,16 +69,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent; public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
private CustomBufferedStream GetStream(bool isRequest) private ICustomStreamReader GetStreamReader(bool isRequest)
{ {
return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream; return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream;
} }
private CustomBinaryReader GetStreamReader(bool isRequest)
{
return isRequest ? ProxyClient.ClientStreamReader : WebSession.ServerConnection.StreamReader;
}
private HttpWriter GetStreamWriter(bool isRequest) private HttpWriter GetStreamWriter(bool isRequest)
{ {
return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter; return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter;
...@@ -92,14 +88,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -92,14 +88,14 @@ namespace Titanium.Web.Proxy.EventArguments
var request = WebSession.Request; var request = WebSession.Request;
//If not already read (not cached yet) // If not already read (not cached yet)
if (!request.IsBodyRead) if (!request.IsBodyRead)
{ {
var body = await ReadBodyAsync(true, cancellationToken); var body = await ReadBodyAsync(true, cancellationToken);
request.Body = body; request.Body = body;
//Now set the flag to true // Now set the flag to true
//So that next time we can deliver body from cache // So that next time we can deliver body from cache
request.IsBodyRead = true; request.IsBodyRead = true;
OnDataSent(body, 0, body.Length); OnDataSent(body, 0, body.Length);
} }
...@@ -110,7 +106,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -110,7 +106,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
internal async Task ClearResponse(CancellationToken cancellationToken) internal async Task ClearResponse(CancellationToken cancellationToken)
{ {
//syphon out the response body from server // syphon out the response body from server
await SyphonOutBodyAsync(false, cancellationToken); await SyphonOutBodyAsync(false, cancellationToken);
WebSession.Response = new Response(); WebSession.Response = new Response();
} }
...@@ -143,14 +139,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -143,14 +139,14 @@ namespace Titanium.Web.Proxy.EventArguments
return; return;
} }
//If not already read (not cached yet) // If not already read (not cached yet)
if (!response.IsBodyRead) if (!response.IsBodyRead)
{ {
var body = await ReadBodyAsync(false, cancellationToken); var body = await ReadBodyAsync(false, cancellationToken);
response.Body = body; response.Body = body;
//Now set the flag to true // Now set the flag to true
//So that next time we can deliver body from cache // So that next time we can deliver body from cache
response.IsBodyRead = true; response.IsBodyRead = true;
OnDataReceived(body, 0, body.Length); OnDataReceived(body, 0, body.Length);
} }
...@@ -200,18 +196,17 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -200,18 +196,17 @@ namespace Titanium.Web.Proxy.EventArguments
long contentLength = request.ContentLength; long contentLength = request.ContentLength;
//send the request body bytes to server // send the request body bytes to server
if (contentLength > 0 && hasMulipartEventSubscribers && request.IsMultipartFormData) if (contentLength > 0 && hasMulipartEventSubscribers && request.IsMultipartFormData)
{ {
var reader = GetStreamReader(true); var reader = GetStreamReader(true);
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType); string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
using (var copyStream = new CopyStream(reader, writer, BufferSize)) using (var copyStream = new CopyStream(reader, writer, BufferSize))
using (var copyStreamReader = new CustomBinaryReader(copyStream, BufferSize))
{ {
while (contentLength > copyStream.ReadBytes) while (contentLength > copyStream.ReadBytes)
{ {
long read = await ReadUntilBoundaryAsync(copyStreamReader, contentLength, boundary, cancellationToken); long read = await ReadUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken);
if (read == 0) if (read == 0)
{ {
break; break;
...@@ -220,7 +215,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -220,7 +215,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (contentLength > copyStream.ReadBytes) if (contentLength > copyStream.ReadBytes)
{ {
var headers = new HeaderCollection(); var headers = new HeaderCollection();
await HeaderParser.ReadHeaders(copyStreamReader, headers, cancellationToken); await HeaderParser.ReadHeaders(copyStream, headers, cancellationToken);
OnMultipartRequestPartSent(boundary, headers); OnMultipartRequestPartSent(boundary, headers);
} }
} }
...@@ -241,8 +236,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -241,8 +236,7 @@ namespace Titanium.Web.Proxy.EventArguments
private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken) private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
var stream = GetStream(isRequest); var stream = GetStreamReader(isRequest);
var reader = GetStreamReader(isRequest);
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
...@@ -250,7 +244,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -250,7 +244,7 @@ namespace Titanium.Web.Proxy.EventArguments
long contentLength = requestResponse.ContentLength; long contentLength = requestResponse.ContentLength;
if (transformation == TransformationMode.None) if (transformation == TransformationMode.None)
{ {
await writer.CopyBodyAsync(reader, isChunked, contentLength, onCopy, cancellationToken); await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken);
return; return;
} }
...@@ -259,23 +253,22 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -259,23 +253,22 @@ namespace Titanium.Web.Proxy.EventArguments
string contentEncoding = requestResponse.ContentEncoding; string contentEncoding = requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, reader, isChunked, contentLength); Stream s = limitedStream = new LimitedStream(stream, isChunked, contentLength);
if (transformation == TransformationMode.Uncompress && contentEncoding != null) if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{ {
s = decompressStream = DecompressionFactory.Create(contentEncoding).GetStream(s); s = decompressStream = DecompressionFactory.Create(contentEncoding, s);
} }
try try
{ {
var bufStream = new CustomBufferedStream(s, BufferSize, true); using (var bufStream = new CustomBufferedStream(s, BufferSize, true))
reader = new CustomBinaryReader(bufStream, BufferSize); {
await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken);
await writer.CopyBodyAsync(reader, false, -1, onCopy, cancellationToken); }
} }
finally finally
{ {
reader?.Dispose();
decompressStream?.Dispose(); decompressStream?.Dispose();
await limitedStream.Finish(); await limitedStream.Finish();
...@@ -287,7 +280,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -287,7 +280,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Read a line from the byte stream /// Read a line from the byte stream
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<long> ReadUntilBoundaryAsync(CustomBinaryReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken) private async Task<long> ReadUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken)
{ {
int bufferDataLength = 0; int bufferDataLength = 0;
...@@ -330,7 +323,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -330,7 +323,7 @@ namespace Titanium.Web.Proxy.EventArguments
if (bufferDataLength == buffer.Length) 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 // 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; const int bytesToKeep = 100;
Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep); Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep);
bufferDataLength = bytesToKeep; bufferDataLength = bytesToKeep;
......
using System; using System;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.EventArguments
protected readonly ExceptionHandler ExceptionFunc; protected readonly ExceptionHandler ExceptionFunc;
/// <summary> /// <summary>
/// Constructor to initialize the proxy /// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary> /// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc) CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
...@@ -50,16 +51,16 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -50,16 +51,16 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
if (RunTime.IsWindows) if (RunTime.IsWindows)
{ {
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; var remoteEndPoint = ClientEndPoint;
//If client is localhost get the process id // If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{ {
var ipVersion = endPoint.IpV6Enabled ? IpVersion.Ipv6 : IpVersion.Ipv4; var ipVersion = endPoint.IpV6Enabled ? IpVersion.Ipv6 : IpVersion.Ipv4;
return TcpHelper.GetProcessIdByLocalPort(ipVersion, remoteEndPoint.Port); return TcpHelper.GetProcessIdByLocalPort(ipVersion, remoteEndPoint.Port);
} }
//can't access process Id of remote request from remote machine // can't access process Id of remote request from remote machine
return -1; return -1;
} }
...@@ -73,10 +74,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -73,10 +74,14 @@ namespace Titanium.Web.Proxy.EventArguments
internal ProxyClient ProxyClient { get; } internal ProxyClient ProxyClient { get; }
/// <summary> /// <summary>
/// Returns a unique Id for this request/response session which is /// Returns a user data for this request/response session which is
/// same as the RequestId of WebSession. /// same as the user data of WebSession.
/// </summary> /// </summary>
public Guid Id => WebSession.RequestId; public object UserData
{
get => WebSession.UserData;
set => WebSession.UserData = value;
}
/// <summary> /// <summary>
/// Does this session uses SSL? /// Does this session uses SSL?
...@@ -86,7 +91,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -86,7 +91,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Client End Point. /// Client End Point.
/// </summary> /// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.ClientConnection.RemoteEndPoint;
/// <summary> /// <summary>
/// A web session corresponding to a single request/response sequence /// A web session corresponding to a single request/response sequence
......
...@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
get => isHttpsConnect ?? get => isHttpsConnect ??
throw new Exception("The value of this property is known in the BeforeTunnectConnectResponse event"); throw new Exception("The value of this property is known in the BeforeTunnectConnectResponse event");
internal set => isHttpsConnect = value; internal set => isHttpsConnect = value;
} }
} }
......
...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Exceptions
public class ProxyAuthorizationException : ProxyException public class ProxyAuthorizationException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance. /// Initializes a new instance of the <see cref="ProxyAuthorizationException" /> class.
/// </summary> /// </summary>
/// <param name="message">Exception message.</param> /// <param name="message">Exception message.</param>
/// <param name="session">The <see cref="SessionEventArgs" /> instance containing the event data.</param> /// <param name="session">The <see cref="SessionEventArgs" /> instance containing the event data.</param>
......
using System;
using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Exceptions
{
/// <summary>
/// Proxy Connection exception.
/// </summary>
public class ProxyConnectException : ProxyException
{
/// <summary>
/// Initializes a new instance of the <see cref="ProxyConnectException" /> class.
/// </summary>
/// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param>
/// <param name="connectEventArgs">Instance of <see cref="EventArguments.TunnelConnectSessionEventArgs" /> associated to the exception</param>
internal ProxyConnectException(string message, Exception innerException, TunnelConnectSessionEventArgs connectEventArgs) : base(
message, innerException)
{
ConnectEventArgs = connectEventArgs;
}
/// <summary>
/// Gets session info associated to the exception.
/// </summary>
/// <remarks>
/// This object properties should not be edited.
/// </remarks>
public TunnelConnectSessionEventArgs ConnectEventArgs { get; }
}
}
...@@ -8,7 +8,8 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -8,7 +8,8 @@ namespace Titanium.Web.Proxy.Exceptions
public abstract class ProxyException : Exception public abstract class ProxyException : Exception
{ {
/// <summary> /// <summary>
/// Instantiate a new instance of this exception - must be invoked by derived classes' constructors /// Initializes a new instance of the <see cref="ProxyException" /> class.
/// - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
protected ProxyException(string message) : base(message) protected ProxyException(string message) : base(message)
...@@ -16,7 +17,8 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -16,7 +17,8 @@ namespace Titanium.Web.Proxy.Exceptions
} }
/// <summary> /// <summary>
/// Instantiate this exception - must be invoked by derived classes' constructors /// Initializes a new instance of the <see cref="ProxyException" /> class.
/// - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Excception message</param> /// <param name="message">Excception message</param>
/// <param name="innerException">Inner exception associated</param> /// <param name="innerException">Inner exception associated</param>
......
...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Exceptions
public class ProxyHttpException : ProxyException public class ProxyHttpException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance /// Initializes a new instance of the <see cref="ProxyHttpException" /> class.
/// </summary> /// </summary>
/// <param name="message">Message for this exception</param> /// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param> /// <param name="innerException">Associated inner exception</param>
......
...@@ -15,26 +15,27 @@ using Titanium.Web.Proxy.Extensions; ...@@ -15,26 +15,27 @@ using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer public partial class ProxyServer
{ {
/// <summary> /// <summary>
/// This is called when client is aware of proxy /// This is called when client is aware of proxy
/// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
/// </summary> /// </summary>
/// <param name="endPoint">The explicit endpoint.</param> /// <param name="endPoint">The explicit endpoint.</param>
/// <param name="tcpClient">The client.</param> /// <param name="clientConnection">The client connection.</param>
/// <returns>The task.</returns> /// <returns>The task.</returns>
private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient) private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
{ {
var cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token; var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize); var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferSize);
var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
try try
...@@ -42,11 +43,11 @@ namespace Titanium.Web.Proxy ...@@ -42,11 +43,11 @@ namespace Titanium.Web.Proxy
string connectHostname = null; string connectHostname = null;
TunnelConnectSessionEventArgs connectArgs = null; TunnelConnectSessionEventArgs connectArgs = null;
//Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream) == 1) if (await HttpHelper.IsConnectMethod(clientStream) == 1)
{ {
//read the first line HTTP command // read the first line HTTP command
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
return; return;
...@@ -64,16 +65,16 @@ namespace Titanium.Web.Proxy ...@@ -64,16 +65,16 @@ namespace Titanium.Web.Proxy
HttpVersion = version HttpVersion = version
}; };
await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers, cancellationToken); await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc); cancellationTokenSource, ExceptionFunc);
connectArgs.ProxyClient.TcpClient = tcpClient; connectArgs.ProxyClient.ClientConnection = clientConnection;
connectArgs.ProxyClient.ClientStream = clientStream; connectArgs.ProxyClient.ClientStream = clientStream;
await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);
//filter out excluded host names // filter out excluded host names
bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl;
if (connectArgs.DenyConnect) if (connectArgs.DenyConnect)
...@@ -88,7 +89,7 @@ namespace Titanium.Web.Proxy ...@@ -88,7 +89,7 @@ namespace Titanium.Web.Proxy
}; };
} }
//send the response // send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
return; return;
...@@ -98,13 +99,13 @@ namespace Titanium.Web.Proxy ...@@ -98,13 +99,13 @@ namespace Titanium.Web.Proxy
{ {
await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc); await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc);
//send the response // send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response, await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
return; return;
} }
//write back successfull CONNECT response // write back successfull CONNECT response
var response = ConnectResponse.CreateSuccessfullConnectResponse(version); var response = ConnectResponse.CreateSuccessfullConnectResponse(version);
// Set ContentLength explicitly to properly handle HTTP 1.0 // Set ContentLength explicitly to properly handle HTTP 1.0
...@@ -135,9 +136,9 @@ namespace Titanium.Web.Proxy ...@@ -135,9 +136,9 @@ namespace Titanium.Web.Proxy
{ {
// test server HTTP/2 support // test server HTTP/2 support
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently // todo: this is a hack, because Titanium does not support HTTP protocol changing currently
using (var connection = await GetServerConnection(connectArgs, true, cancellationToken)) using (var connection = await GetServerConnection(connectArgs, true, SslExtensions.Http2ProtocolAsList, cancellationToken))
{ {
http2Supproted = connection.IsHttp2Supported; http2Supproted = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2;
} }
} }
...@@ -152,7 +153,7 @@ namespace Titanium.Web.Proxy ...@@ -152,7 +153,7 @@ namespace Titanium.Web.Proxy
var certificate = endPoint.GenericCertificate ?? var certificate = endPoint.GenericCertificate ??
await CertificateManager.CreateCertificateAsync(certName); await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate // Successfully managed to authenticate the client using the fake certificate
var options = new SslServerAuthenticationOptions(); var options = new SslServerAuthenticationOptions();
if (http2Supproted) if (http2Supproted)
{ {
...@@ -169,19 +170,20 @@ namespace Titanium.Web.Proxy ...@@ -169,19 +170,20 @@ namespace Titanium.Web.Proxy
options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck;
await sslStream.AuthenticateAsServerAsync(options, cancellationToken); await sslStream.AuthenticateAsServerAsync(options, cancellationToken);
//HTTPS server created - we can now decrypt the client's traffic #if NETCOREAPP2_1
clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif
// HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new Exception(
$"Could'nt authenticate client '{connectHostname}' with fake certificate.", e));
sslStream?.Dispose(); sslStream?.Dispose();
return; throw new ProxyConnectException(
$"Could'nt authenticate client '{connectHostname}' with fake certificate.", e, connectArgs);
} }
if (await HttpHelper.IsConnectMethod(clientStream) == -1) if (await HttpHelper.IsConnectMethod(clientStream) == -1)
...@@ -195,18 +197,18 @@ namespace Titanium.Web.Proxy ...@@ -195,18 +197,18 @@ namespace Titanium.Web.Proxy
throw new Exception("Session was terminated by user."); throw new Exception("Session was terminated by user.");
} }
//Hostname is excluded or it is not an HTTPS connect // Hostname is excluded or it is not an HTTPS connect
if (!decryptSsl || !isClientHello) if (!decryptSsl || !isClientHello)
{ {
//create new connection // create new connection
using (var connection = await GetServerConnection(connectArgs, true, cancellationToken)) using (var connection = await GetServerConnection(connectArgs, true, clientConnection.NegotiatedApplicationProtocol, cancellationToken))
{ {
if (isClientHello) if (isClientHello)
{ {
int available = clientStream.Available; int available = clientStream.Available;
if (available > 0) if (available > 0)
{ {
//send the buffered data // send the buffered data
var data = BufferPool.GetBuffer(BufferSize); var data = BufferPool.GetBuffer(BufferSize);
try try
...@@ -240,68 +242,68 @@ namespace Titanium.Web.Proxy ...@@ -240,68 +242,68 @@ namespace Titanium.Web.Proxy
if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1) if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1)
{ {
// todo // todo
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (httpCmd == "PRI * HTTP/2.0") if (httpCmd == "PRI * HTTP/2.0")
{ {
// HTTP/2 Connection Preface // HTTP/2 Connection Preface
string line = await clientStreamReader.ReadLineAsync(cancellationToken); string line = await clientStream.ReadLineAsync(cancellationToken);
if (line != string.Empty) if (line != string.Empty)
{ {
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
} }
line = await clientStreamReader.ReadLineAsync(cancellationToken); line = await clientStream.ReadLineAsync(cancellationToken);
if (line != "SM") if (line != "SM")
{ {
throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
} }
line = await clientStreamReader.ReadLineAsync(cancellationToken); line = await clientStream.ReadLineAsync(cancellationToken);
if (line != string.Empty) if (line != string.Empty)
{ {
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
} }
//create new connection // create new connection
using (var connection = await GetServerConnection(connectArgs, true, cancellationToken)) using (var connection = await GetServerConnection(connectArgs, true, SslExtensions.Http2ProtocolAsList, cancellationToken))
{ {
await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken); await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken);
await connection.StreamWriter.WriteLineAsync("SM", cancellationToken); await connection.StreamWriter.WriteLineAsync("SM", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken);
await TcpHelper.SendHttp2(clientStream, connection.Stream, BufferSize, #if NETCOREAPP2_1
await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
connectArgs.CancellationTokenSource, ExceptionFunc); connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc);
#endif
} }
} }
} }
//Now create the request // Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, await HandleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
clientStreamWriter, cancellationTokenSource, connectHostname, cancellationTokenSource, connectHostname, connectArgs?.WebSession.ConnectRequest);
connectArgs?.WebSession.ConnectRequest);
} }
catch (ProxyHttpException e) catch (ProxyException e)
{ {
ExceptionFunc(e); OnException(clientStream, e);
} }
catch (IOException e) catch (IOException e)
{ {
ExceptionFunc(new Exception("Connection was aborted", e)); OnException(clientStream, new Exception("Connection was aborted", e));
} }
catch (SocketException e) catch (SocketException e)
{ {
ExceptionFunc(new Exception("Could not connect", e)); OnException(clientStream, new Exception("Could not connect", e));
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new Exception("Error occured in whilst handling the client", e)); OnException(clientStream, new Exception("Error occured in whilst handling the client", e));
} }
finally finally
{ {
clientStreamReader.Dispose();
clientStream.Dispose(); clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested) if (!cancellationTokenSource.IsCancellationRequested)
{ {
......
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
...@@ -13,6 +14,9 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -13,6 +14,9 @@ namespace Titanium.Web.Proxy.Extensions
internal static readonly List<SslApplicationProtocol> Http11ProtocolAsList = internal static readonly List<SslApplicationProtocol> Http11ProtocolAsList =
new List<SslApplicationProtocol> { SslApplicationProtocol.Http11 }; new List<SslApplicationProtocol> { SslApplicationProtocol.Http11 };
internal static readonly List<SslApplicationProtocol> Http2ProtocolAsList =
new List<SslApplicationProtocol> { SslApplicationProtocol.Http2 };
internal static string GetServerName(this ClientHelloInfo clientHelloInfo) internal static string GetServerName(this ClientHelloInfo clientHelloInfo)
{ {
if (clientHelloInfo.Extensions != null && if (clientHelloInfo.Extensions != null &&
...@@ -81,6 +85,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -81,6 +85,7 @@ namespace Titanium.Web.Proxy.Extensions
Http2 Http2
} }
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleType", Justification = "Reviewed.")]
internal class SslClientAuthenticationOptions internal class SslClientAuthenticationOptions
{ {
internal bool AllowRenegotiation { get; set; } internal bool AllowRenegotiation { get; set; }
......
...@@ -31,10 +31,10 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -31,10 +31,10 @@ namespace Titanium.Web.Proxy.Extensions
try try
{ {
//This line is important! // This line is important!
//contributors please don't remove it without discussion // contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion // It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes // due to default TCP CLOSE_WAIT timeout for 4 minutes
if (socketCleanedUpGetter == null || !socketCleanedUpGetter(tcpClient.Client)) if (socketCleanedUpGetter == null || !socketCleanedUpGetter(tcpClient.Client))
{ {
tcpClient.LingerState = new LingerOption(true, 0); tcpClient.LingerState = new LingerOption(true, 0);
......
...@@ -21,13 +21,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -21,13 +21,13 @@ namespace Titanium.Web.Proxy.Helpers
{ {
try try
{ {
//return default if not specified // return default if not specified
if (contentType == null) if (contentType == null)
{ {
return defaultEncoding; return defaultEncoding;
} }
//extract the encoding by finding the charset // extract the encoding by finding the charset
var parameters = contentType.Split(ProxyConstants.SemiColonSplit); var parameters = contentType.Split(ProxyConstants.SemiColonSplit);
foreach (string parameter in parameters) foreach (string parameter in parameters)
{ {
...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.Helpers
if (split.Length == 2 && split[0].Trim().EqualsIgnoreCase(KnownHeaders.ContentTypeCharset)) if (split.Length == 2 && split[0].Trim().EqualsIgnoreCase(KnownHeaders.ContentTypeCharset))
{ {
string value = split[1]; string value = split[1];
if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase)) if (value.EqualsIgnoreCase("x-user-defined"))
{ {
continue; continue;
} }
...@@ -51,11 +51,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -51,11 +51,11 @@ namespace Titanium.Web.Proxy.Helpers
} }
catch catch
{ {
//parsing errors // parsing errors
// ignored // ignored
} }
//return default if not specified // return default if not specified
return defaultEncoding; return defaultEncoding;
} }
...@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -63,7 +63,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
if (contentType != null) if (contentType != null)
{ {
//extract the boundary // extract the boundary
var parameters = contentType.Split(ProxyConstants.SemiColonSplit); var parameters = contentType.Split(ProxyConstants.SemiColonSplit);
foreach (string parameter in parameters) foreach (string parameter in parameters)
{ {
...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
//return null if not specified // return null if not specified
return null; return null;
} }
...@@ -94,14 +94,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -94,14 +94,14 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns> /// <returns></returns>
internal static string GetWildCardDomainName(string hostname) internal static string GetWildCardDomainName(string hostname)
{ {
//only for subdomains we need wild card // only for subdomains we need wild card
//example www.google.com or gstatic.google.com // example www.google.com or gstatic.google.com
//but NOT for google.com // but NOT for google.com
if (hostname.Split(ProxyConstants.DotSplit).Length > 2) if (hostname.Split(ProxyConstants.DotSplit).Length > 2)
{ {
int idx = hostname.IndexOf(ProxyConstants.DotSplit); int idx = hostname.IndexOf(ProxyConstants.DotSplit);
//issue #352 // issue #352
if (hostname.Substring(0, idx).Contains("-")) if (hostname.Substring(0, idx).Contains("-"))
{ {
return hostname; return hostname;
...@@ -111,45 +111,45 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -111,45 +111,45 @@ namespace Titanium.Web.Proxy.Helpers
return "*." + rootDomain; return "*." + rootDomain;
} }
//return as it is // return as it is
return hostname; return hostname;
} }
/// <summary> /// <summary>
/// Determines whether is connect method. /// Determines whether is connect method.
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns> /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsConnectMethod(CustomBufferedStream clientStream) internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader)
{ {
return StartsWith(clientStream, "CONNECT"); return StartsWith(clientStreamReader, "CONNECT");
} }
/// <summary> /// <summary>
/// Determines whether is pri method (HTTP/2). /// Determines whether is pri method (HTTP/2).
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns> /// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(CustomBufferedStream clientStream) internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader)
{ {
return StartsWith(clientStream, "PRI"); return StartsWith(clientStreamReader, "PRI");
} }
/// <summary> /// <summary>
/// Determines whether the stream starts with the given string. /// Determines whether the stream starts with the given string.
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStreamReader">The client stream reader.</param>
/// <param name="expectedStart">The expected start.</param> /// <param name="expectedStart">The expected start.</param>
/// <returns> /// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise /// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns> /// </returns>
private static async Task<int> StartsWith(CustomBufferedStream clientStream, string expectedStart) private static async Task<int> StartsWith(ICustomStreamReader clientStreamReader, string expectedStart)
{ {
bool isExpected = true; bool isExpected = true;
int legthToCheck = 10; int legthToCheck = 10;
for (int i = 0; i < legthToCheck; i++) for (int i = 0; i < legthToCheck; i++)
{ {
int b = await clientStream.PeekByteAsync(i); int b = await clientStreamReader.PeekByteAsync(i);
if (b == -1) if (b == -1)
{ {
return -1; return -1;
......
...@@ -11,17 +11,20 @@ using Titanium.Web.Proxy.Shared; ...@@ -11,17 +11,20 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal class HttpWriter : CustomBinaryWriter internal class HttpWriter : ICustomStreamWriter
{ {
private readonly Stream stream;
private static readonly byte[] newLine = ProxyConstants.NewLine; private static readonly byte[] newLine = ProxyConstants.NewLine;
private static readonly Encoder encoder = Encoding.ASCII.GetEncoder(); private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();
private readonly char[] charBuffer; private readonly char[] charBuffer;
internal HttpWriter(Stream stream, int bufferSize) : base(stream) internal HttpWriter(Stream stream, int bufferSize)
{ {
BufferSize = bufferSize; BufferSize = bufferSize;
this.stream = stream;
// ASCII encoder max byte count is char count + 1 // ASCII encoder max byte count is char count + 1
charBuffer = new char[BufferSize - 1]; charBuffer = new char[BufferSize - 1];
...@@ -62,7 +65,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -62,7 +65,7 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx, cancellationToken); return stream.WriteAsync(buffer, 0, idx, cancellationToken);
} }
finally finally
{ {
...@@ -82,7 +85,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -82,7 +85,7 @@ namespace Titanium.Web.Proxy.Helpers
idx += newLineChars; idx += newLineChars;
} }
return WriteAsync(buffer, 0, idx, cancellationToken); return stream.WriteAsync(buffer, 0, idx, cancellationToken);
} }
} }
...@@ -109,26 +112,26 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -109,26 +112,26 @@ namespace Titanium.Web.Proxy.Helpers
await WriteLineAsync(cancellationToken); await WriteLineAsync(cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
internal async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default) internal async Task WriteAsync(byte[] data, bool flush = false, CancellationToken cancellationToken = default)
{ {
await WriteAsync(data, 0, data.Length, cancellationToken); await stream.WriteAsync(data, 0, data.Length, cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
internal async Task WriteAsync(byte[] data, int offset, int count, bool flush, internal async Task WriteAsync(byte[] data, int offset, int count, bool flush,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
await WriteAsync(data, offset, count, cancellationToken); await stream.WriteAsync(data, offset, count, cancellationToken);
if (flush) if (flush)
{ {
await FlushAsync(cancellationToken); await stream.FlushAsync(cancellationToken);
} }
} }
...@@ -159,22 +162,22 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -159,22 +162,22 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal Task CopyBodyAsync(CustomBinaryReader streamReader, bool isChunked, long contentLength, internal Task CopyBodyAsync(ICustomStreamReader streamReader, bool isChunked, long contentLength,
Action<byte[], int, int> onCopy, CancellationToken cancellationToken) Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{ {
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol // For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (isChunked) if (isChunked)
{ {
return CopyBodyChunkedAsync(streamReader, onCopy, cancellationToken); return CopyBodyChunkedAsync(streamReader, onCopy, cancellationToken);
} }
//http 1.0 or the stream reader limits the stream // http 1.0 or the stream reader limits the stream
if (contentLength == -1) if (contentLength == -1)
{ {
contentLength = long.MaxValue; contentLength = long.MaxValue;
} }
//If not chunked then its easy just read the amount of bytes mentioned in content length header // If not chunked then its easy just read the amount of bytes mentioned in content length header
return CopyBytesFromStream(streamReader, contentLength, onCopy, cancellationToken); return CopyBytesFromStream(streamReader, contentLength, onCopy, cancellationToken);
} }
...@@ -204,7 +207,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -204,7 +207,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task CopyBodyChunkedAsync(CustomBinaryReader reader, Action<byte[], int, int> onCopy, private async Task CopyBodyChunkedAsync(ICustomStreamReader reader, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
while (true) while (true)
...@@ -227,7 +230,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -227,7 +230,7 @@ namespace Titanium.Web.Proxy.Helpers
await WriteLineAsync(cancellationToken); await WriteLineAsync(cancellationToken);
//chunk trail // chunk trail
await reader.ReadLineAsync(cancellationToken); await reader.ReadLineAsync(cancellationToken);
if (chunkSize == 0) if (chunkSize == 0)
...@@ -245,31 +248,39 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -245,31 +248,39 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
private async Task CopyBytesFromStream(CustomBinaryReader reader, long count, Action<byte[], int, int> onCopy, private async Task CopyBytesFromStream(ICustomStreamReader reader, long count, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var buffer = reader.Buffer; var buffer = BufferPool.GetBuffer(BufferSize);
long remainingBytes = count;
while (remainingBytes > 0) try
{ {
int bytesToRead = buffer.Length; long remainingBytes = count;
if (remainingBytes < bytesToRead)
{
bytesToRead = (int)remainingBytes;
}
int bytesRead = await reader.ReadBytesAsync(buffer, bytesToRead, cancellationToken); while (remainingBytes > 0)
if (bytesRead == 0)
{ {
break; int bytesToRead = buffer.Length;
} if (remainingBytes < bytesToRead)
{
bytesToRead = (int)remainingBytes;
}
remainingBytes -= bytesRead; int bytesRead = await reader.ReadAsync(buffer, 0, bytesToRead, cancellationToken);
if (bytesRead == 0)
{
break;
}
await WriteAsync(buffer, 0, bytesRead, cancellationToken); remainingBytes -= bytesRead;
onCopy?.Invoke(buffer, 0, bytesRead); await stream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
onCopy?.Invoke(buffer, 0, bytesRead);
}
}
finally
{
BufferPool.ReturnBuffer(buffer);
} }
} }
...@@ -291,5 +302,33 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -291,5 +302,33 @@ namespace Titanium.Web.Proxy.Helpers
await WriteBodyAsync(body, requestResponse.IsChunked, cancellationToken); await WriteBodyAsync(body, requestResponse.IsChunked, cancellationToken);
} }
} }
/// <summary>When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.</summary>
/// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
/// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
/// <param name="count">The number of bytes to be written to the current stream.</param>
/// <exception cref="T:System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
/// <exception cref="T:System.ArgumentNullException">buffer is null.</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">offset or count is negative.</exception>
/// <exception cref="T:System.IO.IOException">An I/O error occured, such as the specified file cannot be found.</exception>
/// <exception cref="T:System.NotSupportedException">The stream does not support writing.</exception>
/// <exception cref="T:System.ObjectDisposedException"><see cref="M:System.IO.Stream.Write(System.Byte[],System.Int32,System.Int32)"></see> was called after the stream was closed.</exception>
public void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
/// <summary>
/// Asynchronously writes a sequence of bytes to the current stream, advances the current position within this stream by the number of bytes written, and monitors cancellation requests.
/// </summary>
/// <param name="buffer">The buffer to write data from.</param>
/// <param name="offset">The zero-based byte offset in <paramref name="buffer" /> from which to begin copying bytes to the stream.</param>
/// <param name="count">The maximum number of bytes to write.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="P:System.Threading.CancellationToken.None" />.</param>
/// <returns>A task that represents the asynchronous write operation.</returns>
public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return stream.WriteAsync(buffer, offset, count, cancellationToken);
}
} }
} }
...@@ -21,6 +21,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -21,6 +21,7 @@ namespace Titanium.Web.Proxy.Helpers
// get local IP addresses // get local IP addresses
var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); var localIPs = Dns.GetHostAddresses(Dns.GetHostName());
// test if any host IP equals to any local IP or to localhost // test if any host IP equals to any local IP or to localhost
return localIPs.Contains(address); return localIPs.Contains(address);
} }
......
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Microsoft.Win32; using Microsoft.Win32;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -6,7 +7,6 @@ using Titanium.Web.Proxy.Models; ...@@ -6,7 +7,6 @@ using Titanium.Web.Proxy.Models;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal class HttpSystemProxyValue internal class HttpSystemProxyValue
{ {
internal string HostName { get; set; } internal string HostName { get; set; }
...@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -37,6 +37,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Manage system proxy settings /// Manage system proxy settings
/// </summary> /// </summary>
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleType", Justification = "Reviewed.")]
internal class SystemProxyManager internal class SystemProxyManager
{ {
private const string regKeyInternetSettings = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; private const string regKeyInternetSettings = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -66,7 +67,7 @@ namespace Titanium.Web.Proxy.Helpers
return false; return false;
}; };
//On Console exit make sure we also exit the proxy // On Console exit make sure we also exit the proxy
NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true); NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true);
} }
} }
......
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Linq;
using System.Threading; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Text;
using StreamExtended.Helpers; using System.Threading;
using Titanium.Web.Proxy.Extensions; using System.Threading.Tasks;
using StreamExtended.Helpers;
namespace Titanium.Web.Proxy.Helpers using Titanium.Web.Proxy.Extensions;
{
internal enum IpVersion namespace Titanium.Web.Proxy.Helpers
{ {
Ipv4 = 1, internal enum IpVersion
Ipv6 = 2 {
} Ipv4 = 1,
Ipv6 = 2
internal class TcpHelper }
{
/// <summary> internal class TcpHelper
/// Gets the process id by local port number. {
/// </summary> /// <summary>
/// <returns>Process id.</returns> /// Gets the process id by local port number.
internal static unsafe int GetProcessIdByLocalPort(IpVersion ipVersion, int localPort) /// </summary>
{ /// <returns>Process id.</returns>
var tcpTable = IntPtr.Zero; internal static unsafe int GetProcessIdByLocalPort(IpVersion ipVersion, int localPort)
int tcpTableLength = 0; {
var tcpTable = IntPtr.Zero;
int ipVersionValue = ipVersion == IpVersion.Ipv4 ? NativeMethods.AfInet : NativeMethods.AfInet6; int tcpTableLength = 0;
const int allPid = (int)NativeMethods.TcpTableType.OwnerPidAll;
int ipVersionValue = ipVersion == IpVersion.Ipv4 ? NativeMethods.AfInet : NativeMethods.AfInet6;
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, ipVersionValue, allPid, 0) != 0) const int allPid = (int)NativeMethods.TcpTableType.OwnerPidAll;
{
try if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, ipVersionValue, allPid, 0) != 0)
{ {
tcpTable = Marshal.AllocHGlobal(tcpTableLength); try
if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, allPid, {
0) == 0) tcpTable = Marshal.AllocHGlobal(tcpTableLength);
{ if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, ipVersionValue, allPid,
int rowCount = *(int*)tcpTable; 0) == 0)
uint portInNetworkByteOrder = ToNetworkByteOrder((uint)localPort); {
int rowCount = *(int*)tcpTable;
if (ipVersion == IpVersion.Ipv4) uint portInNetworkByteOrder = ToNetworkByteOrder((uint)localPort);
{
var rowPtr = (NativeMethods.TcpRow*)(tcpTable + 4); if (ipVersion == IpVersion.Ipv4)
{
for (int i = 0; i < rowCount; ++i) var rowPtr = (NativeMethods.TcpRow*)(tcpTable + 4);
{
if (rowPtr->localPort == portInNetworkByteOrder) for (int i = 0; i < rowCount; ++i)
{ {
return rowPtr->owningPid; if (rowPtr->localPort == portInNetworkByteOrder)
} {
return rowPtr->owningPid;
rowPtr++; }
}
} rowPtr++;
else }
{ }
var rowPtr = (NativeMethods.Tcp6Row*)(tcpTable + 4); else
{
for (int i = 0; i < rowCount; ++i) var rowPtr = (NativeMethods.Tcp6Row*)(tcpTable + 4);
{
if (rowPtr->localPort == portInNetworkByteOrder) for (int i = 0; i < rowCount; ++i)
{ {
return rowPtr->owningPid; if (rowPtr->localPort == portInNetworkByteOrder)
} {
return rowPtr->owningPid;
rowPtr++; }
}
} rowPtr++;
} }
} }
finally }
{ }
if (tcpTable != IntPtr.Zero) finally
{ {
Marshal.FreeHGlobal(tcpTable); if (tcpTable != IntPtr.Zero)
} {
} Marshal.FreeHGlobal(tcpTable);
} }
}
return 0; }
}
return 0;
/// <summary> }
/// Converts 32-bit integer from native byte order (little-endian)
/// to network byte order for port, /// <summary>
/// switches 0th and 1st bytes, and 2nd and 3rd bytes /// Converts 32-bit integer from native byte order (little-endian)
/// </summary> /// to network byte order for port,
/// <param name="port"></param> /// switches 0th and 1st bytes, and 2nd and 3rd bytes
/// <returns></returns> /// </summary>
private static uint ToNetworkByteOrder(uint port) /// <param name="port"></param>
{ /// <returns></returns>
return ((port >> 8) & 0x00FF00FFu) | ((port << 8) & 0xFF00FF00u); private static uint ToNetworkByteOrder(uint port)
} {
return ((port >> 8) & 0x00FF00FFu) | ((port << 8) & 0xFF00FF00u);
/// <summary> }
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// as prefix /// <summary>
/// Usefull for websocket requests /// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// Asynchronous Programming Model, which does not throw exceptions when the socket is closed /// as prefix
/// </summary> /// Usefull for websocket requests
/// <param name="clientStream"></param> /// Asynchronous Programming Model, which does not throw exceptions when the socket is closed
/// <param name="serverStream"></param> /// </summary>
/// <param name="bufferSize"></param> /// <param name="clientStream"></param>
/// <param name="onDataSend"></param> /// <param name="serverStream"></param>
/// <param name="onDataReceive"></param> /// <param name="bufferSize"></param>
/// <param name="cancellationTokenSource"></param> /// <param name="onDataSend"></param>
/// <param name="exceptionFunc"></param> /// <param name="onDataReceive"></param>
/// <returns></returns> /// <param name="cancellationTokenSource"></param>
internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize, /// <param name="exceptionFunc"></param>
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, /// <returns></returns>
CancellationTokenSource cancellationTokenSource, internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize,
ExceptionHandler exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
{ CancellationTokenSource cancellationTokenSource,
var taskCompletionSource = new TaskCompletionSource<bool>(); ExceptionHandler exceptionFunc)
cancellationTokenSource.Token.Register(() => taskCompletionSource.TrySetResult(true)); {
var taskCompletionSource = new TaskCompletionSource<bool>();
//Now async relay all server=>client & client=>server data cancellationTokenSource.Token.Register(() => taskCompletionSource.TrySetResult(true));
var clientBuffer = BufferPool.GetBuffer(bufferSize);
var serverBuffer = BufferPool.GetBuffer(bufferSize); // Now async relay all server=>client & client=>server data
try var clientBuffer = BufferPool.GetBuffer(bufferSize);
{ var serverBuffer = BufferPool.GetBuffer(bufferSize);
BeginRead(clientStream, serverStream, clientBuffer, onDataSend, cancellationTokenSource, exceptionFunc); try
BeginRead(serverStream, clientStream, serverBuffer, onDataReceive, cancellationTokenSource, {
exceptionFunc); BeginRead(clientStream, serverStream, clientBuffer, onDataSend, cancellationTokenSource, exceptionFunc);
await taskCompletionSource.Task; BeginRead(serverStream, clientStream, serverBuffer, onDataReceive, cancellationTokenSource,
} exceptionFunc);
finally await taskCompletionSource.Task;
{ }
BufferPool.ReturnBuffer(clientBuffer); finally
BufferPool.ReturnBuffer(serverBuffer); {
} BufferPool.ReturnBuffer(clientBuffer);
} BufferPool.ReturnBuffer(serverBuffer);
}
private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, }
Action<byte[], int, int> onCopy, CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc) private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer,
{ Action<byte[], int, int> onCopy, CancellationTokenSource cancellationTokenSource,
if (cancellationTokenSource.IsCancellationRequested) ExceptionHandler exceptionFunc)
{ {
return; if (cancellationTokenSource.IsCancellationRequested)
} {
return;
bool readFlag = false; }
var readCallback = (AsyncCallback)(ar =>
{ bool readFlag = false;
if (cancellationTokenSource.IsCancellationRequested || readFlag) var readCallback = (AsyncCallback)(ar =>
{ {
return; if (cancellationTokenSource.IsCancellationRequested || readFlag)
} {
return;
readFlag = true; }
try readFlag = true;
{
int read = inputStream.EndRead(ar); try
if (read <= 0) {
{ int read = inputStream.EndRead(ar);
cancellationTokenSource.Cancel(); if (read <= 0)
return; {
} cancellationTokenSource.Cancel();
return;
onCopy?.Invoke(buffer, 0, read); }
var writeCallback = (AsyncCallback)(ar2 => onCopy?.Invoke(buffer, 0, read);
{
if (cancellationTokenSource.IsCancellationRequested) var writeCallback = (AsyncCallback)(ar2 =>
{ {
return; if (cancellationTokenSource.IsCancellationRequested)
} {
return;
try }
{
outputStream.EndWrite(ar2); try
BeginRead(inputStream, outputStream, buffer, onCopy, cancellationTokenSource, {
exceptionFunc); outputStream.EndWrite(ar2);
} BeginRead(inputStream, outputStream, buffer, onCopy, cancellationTokenSource,
catch (IOException ex) exceptionFunc);
{ }
cancellationTokenSource.Cancel(); catch (IOException ex)
exceptionFunc(ex); {
} cancellationTokenSource.Cancel();
}); exceptionFunc(ex);
}
outputStream.BeginWrite(buffer, 0, read, writeCallback, null); });
}
catch (IOException ex) outputStream.BeginWrite(buffer, 0, read, writeCallback, null);
{ }
cancellationTokenSource.Cancel(); catch (IOException ex)
exceptionFunc(ex); {
} cancellationTokenSource.Cancel();
}); exceptionFunc(ex);
}
var readResult = inputStream.BeginRead(buffer, 0, buffer.Length, readCallback, null); });
if (readResult.CompletedSynchronously)
{ var readResult = inputStream.BeginRead(buffer, 0, buffer.Length, readCallback, null);
readCallback(readResult); if (readResult.CompletedSynchronously)
} {
} readCallback(readResult);
}
/// <summary> }
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// as prefix /// <summary>
/// Usefull for websocket requests /// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// Task-based Asynchronous Pattern /// as prefix
/// </summary> /// Usefull for websocket requests
/// <param name="clientStream"></param> /// Task-based Asynchronous Pattern
/// <param name="serverStream"></param> /// </summary>
/// <param name="bufferSize"></param> /// <param name="clientStream"></param>
/// <param name="onDataSend"></param> /// <param name="serverStream"></param>
/// <param name="onDataReceive"></param> /// <param name="bufferSize"></param>
/// <param name="cancellationTokenSource"></param> /// <param name="onDataSend"></param>
/// <param name="exceptionFunc"></param> /// <param name="onDataReceive"></param>
/// <returns></returns> /// <param name="cancellationTokenSource"></param>
private static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize, /// <param name="exceptionFunc"></param>
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, /// <returns></returns>
CancellationTokenSource cancellationTokenSource, private static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize,
ExceptionHandler exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
{ CancellationTokenSource cancellationTokenSource,
//Now async relay all server=>client & client=>server data ExceptionHandler exceptionFunc)
var sendRelay = {
clientStream.CopyToAsync(serverStream, onDataSend, bufferSize, cancellationTokenSource.Token); // Now async relay all server=>client & client=>server data
var receiveRelay = var sendRelay =
serverStream.CopyToAsync(clientStream, onDataReceive, bufferSize, cancellationTokenSource.Token); clientStream.CopyToAsync(serverStream, onDataSend, bufferSize, cancellationTokenSource.Token);
var receiveRelay =
await Task.WhenAny(sendRelay, receiveRelay); serverStream.CopyToAsync(clientStream, onDataReceive, bufferSize, cancellationTokenSource.Token);
cancellationTokenSource.Cancel();
await Task.WhenAny(sendRelay, receiveRelay);
await Task.WhenAll(sendRelay, receiveRelay); cancellationTokenSource.Cancel();
}
await Task.WhenAll(sendRelay, receiveRelay);
/// <summary> }
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// as prefix /// <summary>
/// Usefull for websocket requests /// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// </summary> /// as prefix
/// <param name="clientStream"></param> /// Usefull for websocket requests
/// <param name="serverStream"></param> /// </summary>
/// <param name="bufferSize"></param> /// <param name="clientStream"></param>
/// <param name="onDataSend"></param> /// <param name="serverStream"></param>
/// <param name="onDataReceive"></param> /// <param name="bufferSize"></param>
/// <param name="cancellationTokenSource"></param> /// <param name="onDataSend"></param>
/// <param name="exceptionFunc"></param> /// <param name="onDataReceive"></param>
/// <returns></returns> /// <param name="cancellationTokenSource"></param>
internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize, /// <param name="exceptionFunc"></param>
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, /// <returns></returns>
CancellationTokenSource cancellationTokenSource, internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
ExceptionHandler exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
{ CancellationTokenSource cancellationTokenSource,
// todo: fix APM mode ExceptionHandler exceptionFunc)
return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, {
cancellationTokenSource, // todo: fix APM mode
exceptionFunc); return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive,
} cancellationTokenSource,
exceptionFunc);
/// <summary> }
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers }
/// as prefix }
/// Usefull for websocket requests
/// Task-based Asynchronous Pattern
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendHttp2(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
{
var connectionId = Guid.NewGuid();
//Now async relay all server=>client & client=>server data
var sendRelay =
CopyHttp2FrameAsync(clientStream, serverStream, onDataSend, bufferSize, connectionId,
cancellationTokenSource.Token);
var receiveRelay =
CopyHttp2FrameAsync(serverStream, clientStream, onDataReceive, bufferSize, connectionId,
cancellationTokenSource.Token);
await Task.WhenAny(sendRelay, receiveRelay);
cancellationTokenSource.Cancel();
await Task.WhenAll(sendRelay, receiveRelay);
}
private static async Task CopyHttp2FrameAsync(Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, Guid connectionId, CancellationToken cancellationToken)
{
var headerBuffer = new byte[9];
var buffer = new byte[32768];
while (true)
{
int read = await ForceRead(input, headerBuffer, 0, 9, cancellationToken);
if (read != 9)
{
return;
}
int length = (headerBuffer[0] << 16) + (headerBuffer[1] << 8) + headerBuffer[2];
byte type = headerBuffer[3];
byte flags = headerBuffer[4];
int streamId = ((headerBuffer[5] & 0x7f) << 24) + (headerBuffer[6] << 16) + (headerBuffer[7] << 8) +
headerBuffer[8];
read = await ForceRead(input, buffer, 0, length, cancellationToken);
if (read != length)
{
return;
}
await output.WriteAsync(headerBuffer, 0, headerBuffer.Length, cancellationToken);
await output.WriteAsync(buffer, 0, length, cancellationToken);
/*using (var fs = new System.IO.FileStream($@"c:\11\{connectionId}.{streamId}.dat", FileMode.Append))
{
fs.Write(headerBuffer, 0, headerBuffer.Length);
fs.Write(buffer, 0, length);
}*/
}
}
private static async Task<int> ForceRead(Stream input, byte[] buffer, int offset, int bytesToRead,
CancellationToken cancellationToken)
{
int totalRead = 0;
while (bytesToRead > 0)
{
int read = await input.ReadAsync(buffer, offset, bytesToRead, cancellationToken);
if (read == -1)
{
break;
}
totalRead += read;
bytesToRead -= read;
offset += read;
}
return totalRead;
}
}
}
...@@ -296,7 +296,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -296,7 +296,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
internal void FixProxyHeaders() internal void FixProxyHeaders()
{ {
//If proxy-connection close was returned inform to close the connection // If proxy-connection close was returned inform to close the connection
string proxyHeader = GetHeaderValueOrNull(KnownHeaders.ProxyConnection); string proxyHeader = GetHeaderValueOrNull(KnownHeaders.ProxyConnection);
RemoveHeader(KnownHeaders.ProxyConnection); RemoveHeader(KnownHeaders.ProxyConnection);
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection, internal static async Task ReadHeaders(ICustomStreamReader reader, HeaderCollection headerCollection,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
string tmpLine; string tmpLine;
......
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading; using System.Threading;
...@@ -20,7 +21,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -20,7 +21,6 @@ namespace Titanium.Web.Proxy.Http
{ {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
RequestId = Guid.NewGuid();
Request = request ?? new Request(); Request = request ?? new Request();
Response = response ?? new Response(); Response = response ?? new Response();
} }
...@@ -28,12 +28,17 @@ namespace Titanium.Web.Proxy.Http ...@@ -28,12 +28,17 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
internal TcpConnection ServerConnection { get; set; } internal TcpServerConnection ServerConnection { get; set; }
/// <summary> /// <summary>
/// Request ID. /// Stores internal data for the session.
/// </summary> /// </summary>
public Guid RequestId { get; } internal InternalDataStore Data { get; } = new InternalDataStore();
/// <summary>
/// Gets or sets the user data.
/// </summary>
public object UserData { get; set; }
/// <summary> /// <summary>
/// Override UpStreamEndPoint for this request; Local NIC via request is made /// Override UpStreamEndPoint for this request; Local NIC via request is made
...@@ -69,11 +74,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -69,11 +74,11 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Set the tcp connection to server used by this webclient /// Set the tcp connection to server used by this webclient
/// </summary> /// </summary>
/// <param name="connection">Instance of <see cref="TcpConnection" /></param> /// <param name="serverConnection">Instance of <see cref="TcpServerConnection" /></param>
internal void SetConnection(TcpConnection connection) internal void SetConnection(TcpServerConnection serverConnection)
{ {
connection.LastAccess = DateTime.Now; serverConnection.LastAccess = DateTime.Now;
ServerConnection = connection; ServerConnection = serverConnection;
} }
/// <summary> /// <summary>
...@@ -89,13 +94,12 @@ namespace Titanium.Web.Proxy.Http ...@@ -89,13 +94,12 @@ namespace Titanium.Web.Proxy.Http
var writer = ServerConnection.StreamWriter; var writer = ServerConnection.StreamWriter;
//prepare the request & headers // prepare the request & headers
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery, useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
Request.HttpVersion), cancellationToken); Request.HttpVersion), cancellationToken);
// Send Authentication to Upstream proxy if needed
//Send Authentication to Upstream proxy if needed
if (!isTransparent && upstreamProxy != null if (!isTransparent && upstreamProxy != null
&& ServerConnection.IsHttps == false && ServerConnection.IsHttps == false
&& !string.IsNullOrEmpty(upstreamProxy.UserName) && !string.IsNullOrEmpty(upstreamProxy.UserName)
...@@ -106,7 +110,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -106,7 +110,7 @@ namespace Titanium.Web.Proxy.Http
.WriteToStreamAsync(writer, cancellationToken); .WriteToStreamAsync(writer, cancellationToken);
} }
//write request headers // write request headers
foreach (var header in Request.Headers) foreach (var header in Request.Headers)
{ {
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization) if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
...@@ -121,23 +125,23 @@ namespace Titanium.Web.Proxy.Http ...@@ -121,23 +125,23 @@ namespace Titanium.Web.Proxy.Http
{ {
if (Request.ExpectContinue) if (Request.ExpectContinue)
{ {
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription); out string responseStatusDescription);
//find if server is willing for expect continue // find if server is willing for expect continue
if (responseStatusCode == (int)HttpStatusCode.Continue if (responseStatusCode == (int)HttpStatusCode.Continue
&& responseStatusDescription.EqualsIgnoreCase("continue")) && responseStatusDescription.EqualsIgnoreCase("continue"))
{ {
Request.Is100Continue = true; Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
&& responseStatusDescription.EqualsIgnoreCase("expectation failed")) && responseStatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
Request.ExpectationFailed = true; Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
} }
} }
...@@ -149,13 +153,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -149,13 +153,13 @@ namespace Titanium.Web.Proxy.Http
/// <returns></returns> /// <returns></returns>
internal async Task ReceiveResponse(CancellationToken cancellationToken) internal async Task ReceiveResponse(CancellationToken cancellationToken)
{ {
//return if this is already read // return if this is already read
if (Response.StatusCode != 0) if (Response.StatusCode != 0)
{ {
return; return;
} }
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null) if (httpStatus == null)
{ {
throw new IOException(); throw new IOException();
...@@ -163,7 +167,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -163,7 +167,7 @@ namespace Titanium.Web.Proxy.Http
if (httpStatus == string.Empty) if (httpStatus == string.Empty)
{ {
httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
} }
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
...@@ -172,16 +176,16 @@ namespace Titanium.Web.Proxy.Http ...@@ -172,16 +176,16 @@ namespace Titanium.Web.Proxy.Http
Response.StatusCode = statusCode; Response.StatusCode = statusCode;
Response.StatusDescription = statusDescription; Response.StatusDescription = statusDescription;
//For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request // For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
if (Response.StatusCode == (int)HttpStatusCode.Continue if (Response.StatusCode == (int)HttpStatusCode.Continue
&& Response.StatusDescription.EqualsIgnoreCase("continue")) && Response.StatusDescription.EqualsIgnoreCase("continue"))
{ {
//Read the next line after 100-continue // Read the next line after 100-continue
Response.Is100Continue = true; Response.Is100Continue = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
//now receive response // now receive response
await ReceiveResponse(cancellationToken); await ReceiveResponse(cancellationToken);
return; return;
} }
...@@ -189,18 +193,18 @@ namespace Titanium.Web.Proxy.Http ...@@ -189,18 +193,18 @@ namespace Titanium.Web.Proxy.Http
if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed
&& Response.StatusDescription.EqualsIgnoreCase("expectation failed")) && Response.StatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
//read next line after expectation failed response // read next line after expectation failed response
Response.ExpectationFailed = true; Response.ExpectationFailed = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(cancellationToken); await ServerConnection.Stream.ReadLineAsync(cancellationToken);
//now receive response // now receive response
await ReceiveResponse(cancellationToken); await ReceiveResponse(cancellationToken);
return; return;
} }
//Read the response headers in to unique and non-unique header collections // Read the response headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers, cancellationToken); await HeaderParser.ReadHeaders(ServerConnection.Stream, Response.Headers, cancellationToken);
} }
/// <summary> /// <summary>
......
using System.Collections.Generic;
namespace Titanium.Web.Proxy.Http
{
class InternalDataStore : Dictionary<string, object>
{
public bool TryGetValueAs<T>(string key, out T value)
{
bool result = TryGetValue(key, out var value1);
if (result)
{
value = (T)value1;
}
else
{
value = default;
}
return result;
}
public T GetAs<T>(string key)
{
return (T)this[key];
}
}
}
\ No newline at end of file
...@@ -43,19 +43,19 @@ namespace Titanium.Web.Proxy.Http ...@@ -43,19 +43,19 @@ namespace Titanium.Web.Proxy.Http
{ {
long contentLength = ContentLength; long contentLength = ContentLength;
//If content length is set to 0 the request has no body // If content length is set to 0 the request has no body
if (contentLength == 0) if (contentLength == 0)
{ {
return false; return false;
} }
//Has body only if request is chunked or content length >0 // Has body only if request is chunked or content length >0
if (IsChunked || contentLength > 0) if (IsChunked || contentLength > 0)
{ {
return true; return true;
} }
//has body if POST and when version is http/1.0 // has body if POST and when version is http/1.0
if (Method == "POST" && HttpVersion == HttpHeader.Version10) if (Method == "POST" && HttpVersion == HttpHeader.Version10)
{ {
return true; return true;
...@@ -157,7 +157,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -157,7 +157,7 @@ namespace Titanium.Web.Proxy.Http
return; return;
} }
//GET request don't have a request body to read // GET request don't have a request body to read
if (!HasBody) if (!HasBody)
{ {
throw new BodyNotFoundException("Request don't have a body. " + throw new BodyNotFoundException("Request don't have a body. " +
...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Http
internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl, internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl,
out Version version) out Version version)
{ {
//break up the line into three components (method, remote URL & Http Version) // break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
if (httpCmdSplit.Length < 2) if (httpCmdSplit.Length < 2)
...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Http
throw new Exception("Invalid HTTP request line: " + httpCmd); throw new Exception("Invalid HTTP request line: " + httpCmd);
} }
//Find the request Verb // Find the request Verb
httpMethod = httpCmdSplit[0]; httpMethod = httpCmdSplit[0];
if (!IsAllUpper(httpMethod)) if (!IsAllUpper(httpMethod))
{ {
...@@ -206,13 +206,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -206,13 +206,13 @@ namespace Titanium.Web.Proxy.Http
httpUrl = httpCmdSplit[1]; httpUrl = httpCmdSplit[1];
//parse the HTTP version // parse the HTTP version
version = HttpHeader.Version11; version = HttpHeader.Version11;
if (httpCmdSplit.Length == 3) if (httpCmdSplit.Length == 3)
{ {
string httpVersion = httpCmdSplit[2].Trim(); string httpVersion = httpCmdSplit[2].Trim();
if (string.Equals(httpVersion, "HTTP/1.0", StringComparison.OrdinalIgnoreCase)) if (httpVersion.EqualsIgnoreCase("HTTP/1.0"))
{ {
version = HttpHeader.Version10; version = HttpHeader.Version10;
} }
......
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.Compression;
...@@ -14,7 +15,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -14,7 +15,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Cached body content as byte array. /// Cached body content as byte array.
/// </summary> /// </summary>
protected byte[] BodyInternal; protected byte[] BodyInternal { get; private set; }
/// <summary> /// <summary>
/// Cached body as string. /// Cached body as string.
...@@ -24,7 +25,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -24,7 +25,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters /// Store weather the original request/response has body or not, since the user may change the parameters
/// </summary> /// </summary>
internal bool OriginalHasBody; internal bool OriginalHasBody { get; set; }
/// <summary> /// <summary>
/// Keeps the body data after the session is finished. /// Keeps the body data after the session is finished.
...@@ -62,6 +63,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -62,6 +63,7 @@ namespace Titanium.Web.Proxy.Http
return -1; return -1;
} }
set set
{ {
if (value >= 0) if (value >= 0)
...@@ -105,6 +107,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -105,6 +107,7 @@ namespace Titanium.Web.Proxy.Http
string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.TransferEncoding); string headerValue = Headers.GetHeaderValueOrNull(KnownHeaders.TransferEncoding);
return headerValue != null && headerValue.ContainsIgnoreCase(KnownHeaders.TransferEncodingChunked); return headerValue != null && headerValue.ContainsIgnoreCase(KnownHeaders.TransferEncodingChunked);
} }
set set
{ {
if (value) if (value)
...@@ -135,12 +138,13 @@ namespace Titanium.Web.Proxy.Http ...@@ -135,12 +138,13 @@ namespace Titanium.Web.Proxy.Http
EnsureBodyAvailable(); EnsureBodyAvailable();
return BodyInternal; return BodyInternal;
} }
internal set internal set
{ {
BodyInternal = value; BodyInternal = value;
bodyString = null; bodyString = null;
//If there is a content length header update it // If there is a content length header update it
UpdateContentLength(); UpdateContentLength();
} }
} }
...@@ -177,10 +181,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -177,10 +181,9 @@ namespace Titanium.Web.Proxy.Http
/// <returns></returns> /// <returns></returns>
internal byte[] GetCompressedBody(string encodingType, byte[] body) internal byte[] GetCompressedBody(string encodingType, byte[] body)
{ {
var compressor = CompressionFactory.GetCompression(encodingType);
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
using (var zip = compressor.GetStream(ms)) using (var zip = CompressionFactory.Create(encodingType, ms))
{ {
zip.Write(body, 0, body.Length); zip.Write(body, 0, body.Length);
} }
......
...@@ -47,21 +47,21 @@ namespace Titanium.Web.Proxy.Http ...@@ -47,21 +47,21 @@ namespace Titanium.Web.Proxy.Http
{ {
long contentLength = ContentLength; long contentLength = ContentLength;
//If content length is set to 0 the response has no body // If content length is set to 0 the response has no body
if (contentLength == 0) if (contentLength == 0)
{ {
return false; return false;
} }
//Has body only if response is chunked or content length >0 // Has body only if response is chunked or content length >0
//If none are true then check if connection:close header exist, if so write response until server or client terminates the connection // If none are true then check if connection:close header exist, if so write response until server or client terminates the connection
if (IsChunked || contentLength > 0 || !KeepAlive) if (IsChunked || contentLength > 0 || !KeepAlive)
{ {
return true; return true;
} }
//has response if connection:keep-alive header exist and when version is http/1.0 // has response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream) // Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
if (KeepAlive && HttpVersion == HttpHeader.Version10) if (KeepAlive && HttpVersion == HttpHeader.Version10)
{ {
return true; return true;
...@@ -155,7 +155,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -155,7 +155,7 @@ namespace Titanium.Web.Proxy.Http
string httpVersion = httpResult[0]; string httpVersion = httpResult[0];
version = HttpHeader.Version11; version = HttpHeader.Version11;
if (string.Equals(httpVersion, "HTTP/1.0", StringComparison.OrdinalIgnoreCase)) if (httpVersion.EqualsIgnoreCase("HTTP/1.0"))
{ {
version = HttpHeader.Version10; version = HttpHeader.Version10;
} }
......
...@@ -3,9 +3,9 @@ using System.Web; ...@@ -3,9 +3,9 @@ using System.Web;
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary> /// <summary>
/// Anything other than a 200 or 302 response /// Anything other than a 200 or 302 response
/// </summary> /// </summary>
public class GenericResponse : Response public class GenericResponse : Response
{ {
/// <summary> /// <summary>
...@@ -19,8 +19,8 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -19,8 +19,8 @@ namespace Titanium.Web.Proxy.Http.Responses
#if NET45 #if NET45
StatusDescription = HttpWorkerRequest.GetStatusDescription(StatusCode); StatusDescription = HttpWorkerRequest.GetStatusDescription(StatusCode);
#else #else
//todo: this is not really correct, status description should contain spaces, too // todo: this is not really correct, status description should contain spaces, too
//see: https://tools.ietf.org/html/rfc7231#section-6.1 // see: https://tools.ietf.org/html/rfc7231#section-6.1
StatusDescription = status.ToString(); StatusDescription = status.ToString();
#endif #endif
} }
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Http.Responses
public sealed class RedirectResponse : Response public sealed class RedirectResponse : Response
{ {
/// <summary> /// <summary>
/// Constructor. /// Initializes a new instance of the <see cref="RedirectResponse" /> class.
/// </summary> /// </summary>
public RedirectResponse() public RedirectResponse()
{ {
......
...@@ -95,7 +95,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -95,7 +95,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (hostName != null) if (hostName != null)
{ {
//add subject alternative names // add subject alternative names
var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName) }; var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName) };
var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames); var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
......
...@@ -64,7 +64,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -64,7 +64,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate"); typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate");
typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment"); typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment");
//for alternative names // for alternative names
typeAltNamesCollection = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames"); typeAltNamesCollection = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames");
typeExtNames = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames"); typeExtNames = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames");
typeCAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName"); typeCAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName");
...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (!isRoot) if (!isRoot)
{ {
//add alternative names // add alternative names
// https://forums.iis.net/t/1180823.aspx // https://forums.iis.net/t/1180823.aspx
var altNameCollection = Activator.CreateInstance(typeAltNamesCollection); var altNameCollection = Activator.CreateInstance(typeAltNamesCollection);
...@@ -284,15 +284,19 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -284,15 +284,19 @@ namespace Titanium.Web.Proxy.Network.Certificate
cancellationToken).Result; cancellationToken).Result;
} }
//Subject // Subject
string fullSubject = $"CN={sSubjectCN}"; string fullSubject = $"CN={sSubjectCN}";
//Sig Algo
// Sig Algo
const string hashAlgo = "SHA256"; const string hashAlgo = "SHA256";
//Grace Days
// Grace Days
const int graceDays = -366; const int graceDays = -366;
//ValiDays
// ValiDays
const int validDays = 1825; const int validDays = 1825;
//KeyLength
// KeyLength
const int keyLength = 2048; const int keyLength = 2048;
var graceTime = DateTime.Now.AddDays(graceDays); var graceTime = DateTime.Now.AddDays(graceDays);
......
...@@ -57,9 +57,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -57,9 +57,9 @@ namespace Titanium.Web.Proxy.Network
private X509Certificate2 rootCertificate; private X509Certificate2 rootCertificate;
private string rootCertificateName; private string rootCertificateName;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CertificateManager"/> class.
/// </summary> /// </summary>
/// <param name="rootCertificateName"></param> /// <param name="rootCertificateName"></param>
/// <param name="rootCertificateIssuerName"></param> /// <param name="rootCertificateIssuerName"></param>
...@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Network
get => engine; get => engine;
set set
{ {
//For Mono (or Non-Windows) only Bouncy Castle is supported // For Mono (or Non-Windows) only Bouncy Castle is supported
if (!RunTime.IsWindows || RunTime.IsRunningOnMono) if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
{ {
value = CertificateEngine.BouncyCastle; value = CertificateEngine.BouncyCastle;
...@@ -241,8 +241,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -241,8 +241,7 @@ namespace Titanium.Web.Proxy.Network
public void Dispose() public void Dispose()
{ {
} }
private string GetRootCertificateDirectory() private string GetRootCertificateDirectory()
{ {
string assemblyLocation = Assembly.GetExecutingAssembly().Location; string assemblyLocation = Assembly.GetExecutingAssembly().Location;
...@@ -254,7 +253,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -254,7 +253,7 @@ namespace Titanium.Web.Proxy.Network
} }
string path = Path.GetDirectoryName(assemblyLocation); string path = Path.GetDirectoryName(assemblyLocation);
if (null == path) if (path == null)
{ {
throw new NullReferenceException(); throw new NullReferenceException();
} }
...@@ -322,22 +321,18 @@ namespace Titanium.Web.Proxy.Network ...@@ -322,22 +321,18 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
/// <param name="storeName"></param> /// <param name="storeName"></param>
/// <param name="storeLocation"></param> /// <param name="storeLocation"></param>
/// <returns></returns>
private void InstallCertificate(StoreName storeName, StoreLocation storeLocation) private void InstallCertificate(StoreName storeName, StoreLocation storeLocation)
{ {
if (RootCertificate == null) if (RootCertificate == null)
{ {
exceptionFunc( exceptionFunc(new Exception("Could not install certificate as it is null or empty."));
new Exception("Could not install certificate"
+ " as it is null or empty."));
return; return;
} }
var x509Store = new X509Store(storeName, storeLocation); var x509Store = new X509Store(storeName, storeLocation);
//TODO // todo
//also it should do not duplicate if certificate already exists // also it should do not duplicate if certificate already exists
try try
{ {
x509Store.Open(OpenFlags.ReadWrite); x509Store.Open(OpenFlags.ReadWrite);
...@@ -362,16 +357,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -362,16 +357,12 @@ namespace Titanium.Web.Proxy.Network
/// <param name="storeName"></param> /// <param name="storeName"></param>
/// <param name="storeLocation"></param> /// <param name="storeLocation"></param>
/// <param name="certificate"></param> /// <param name="certificate"></param>
/// <returns></returns>
private void UninstallCertificate(StoreName storeName, StoreLocation storeLocation, private void UninstallCertificate(StoreName storeName, StoreLocation storeLocation,
X509Certificate2 certificate) X509Certificate2 certificate)
{ {
if (certificate == null) if (certificate == null)
{ {
exceptionFunc( exceptionFunc(new Exception("Could not remove certificate as it is null or empty."));
new Exception("Could not remove certificate"
+ " as it is null or empty."));
return; return;
} }
...@@ -434,7 +425,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -434,7 +425,7 @@ namespace Titanium.Web.Proxy.Network
{ {
certificate = MakeCertificate(certificateName, false); certificate = MakeCertificate(certificateName, false);
//store as cache // store as cache
Task.Run(() => Task.Run(() =>
{ {
try try
...@@ -453,9 +444,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -453,9 +444,9 @@ namespace Titanium.Web.Proxy.Network
{ {
certificate = new X509Certificate2(certificatePath, string.Empty, StorageFlag); certificate = new X509Certificate2(certificatePath, string.Empty, StorageFlag);
} }
//if load failed create again
catch catch
{ {
// if load failed create again
certificate = MakeCertificate(certificateName, false); certificate = MakeCertificate(certificateName, false);
} }
} }
...@@ -480,21 +471,21 @@ namespace Titanium.Web.Proxy.Network ...@@ -480,21 +471,21 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns> /// <returns></returns>
internal async Task<X509Certificate2> CreateCertificateAsync(string certificateName) internal async Task<X509Certificate2> CreateCertificateAsync(string certificateName)
{ {
//check in cache first // check in cache first
if (certificateCache.TryGetValue(certificateName, out var cached)) if (certificateCache.TryGetValue(certificateName, out var cached))
{ {
cached.LastAccess = DateTime.Now; cached.LastAccess = DateTime.Now;
return cached.Certificate; return cached.Certificate;
} }
//handle burst requests with same certificate name // handle burst requests with same certificate name
//by checking for existing task for same certificate name // by checking for existing task for same certificate name
if (pendingCertificateCreationTasks.TryGetValue(certificateName, out var task)) if (pendingCertificateCreationTasks.TryGetValue(certificateName, out var task))
{ {
return await task; return await task;
} }
//run certificate creation task & add it to pending tasks // run certificate creation task & add it to pending tasks
task = Task.Run(() => task = Task.Run(() =>
{ {
var result = CreateCertificate(certificateName, false); var result = CreateCertificate(certificateName, false);
...@@ -510,7 +501,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -510,7 +501,7 @@ namespace Titanium.Web.Proxy.Network
}); });
pendingCertificateCreationTasks.TryAdd(certificateName, task); pendingCertificateCreationTasks.TryAdd(certificateName, task);
//cleanup pending tasks & return result // cleanup pending tasks & return result
var certificate = await task; var certificate = await task;
pendingCertificateCreationTasks.TryRemove(certificateName, out task); pendingCertificateCreationTasks.TryRemove(certificateName, out task);
...@@ -534,12 +525,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -534,12 +525,11 @@ namespace Titanium.Web.Proxy.Network
certificateCache.TryRemove(cache.Key, out _); certificateCache.TryRemove(cache.Key, out _);
} }
//after a minute come back to check for outdated certificates in cache // after a minute come back to check for outdated certificates in cache
await Task.Delay(1000 * 60); await Task.Delay(1000 * 60);
} }
} }
/// <summary> /// <summary>
/// Stops the certificate cache clear process /// Stops the certificate cache clear process
/// </summary> /// </summary>
...@@ -665,20 +655,20 @@ namespace Titanium.Web.Proxy.Network ...@@ -665,20 +655,20 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
public void TrustRootCertificate(bool machineTrusted = false) public void TrustRootCertificate(bool machineTrusted = false)
{ {
//currentUser\personal // currentUser\personal
InstallCertificate(StoreName.My, StoreLocation.CurrentUser); InstallCertificate(StoreName.My, StoreLocation.CurrentUser);
if (!machineTrusted) if (!machineTrusted)
{ {
//currentUser\Root // currentUser\Root
InstallCertificate(StoreName.Root, StoreLocation.CurrentUser); InstallCertificate(StoreName.Root, StoreLocation.CurrentUser);
} }
else else
{ {
//current system // current system
InstallCertificate(StoreName.My, StoreLocation.LocalMachine); InstallCertificate(StoreName.My, StoreLocation.LocalMachine);
//this adds to both currentUser\Root & currentMachine\Root // this adds to both currentUser\Root & currentMachine\Root
InstallCertificate(StoreName.Root, StoreLocation.LocalMachine); InstallCertificate(StoreName.Root, StoreLocation.LocalMachine);
} }
} }
...@@ -695,13 +685,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -695,13 +685,13 @@ namespace Titanium.Web.Proxy.Network
return false; return false;
} }
//currentUser\Personal // currentUser\Personal
InstallCertificate(StoreName.My, StoreLocation.CurrentUser); InstallCertificate(StoreName.My, StoreLocation.CurrentUser);
string pfxFileName = Path.GetTempFileName(); string pfxFileName = Path.GetTempFileName();
File.WriteAllBytes(pfxFileName, RootCertificate.Export(X509ContentType.Pkcs12, PfxPassword)); File.WriteAllBytes(pfxFileName, RootCertificate.Export(X509ContentType.Pkcs12, PfxPassword));
//currentUser\Root, currentMachine\Personal & currentMachine\Root // currentUser\Root, currentMachine\Personal & currentMachine\Root
var info = new ProcessStartInfo var info = new ProcessStartInfo
{ {
FileName = "certutil.exe", FileName = "certutil.exe",
...@@ -785,8 +775,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -785,8 +775,7 @@ namespace Titanium.Web.Proxy.Network
EnsureRootCertificate(); EnsureRootCertificate();
} }
/// <summary> /// <summary>
/// Determines whether the root certificate is trusted. /// Determines whether the root certificate is trusted.
/// </summary> /// </summary>
...@@ -810,20 +799,20 @@ namespace Titanium.Web.Proxy.Network ...@@ -810,20 +799,20 @@ namespace Titanium.Web.Proxy.Network
/// <param name="machineTrusted">Should also remove from machine store?</param> /// <param name="machineTrusted">Should also remove from machine store?</param>
public void RemoveTrustedRootCertificate(bool machineTrusted = false) public void RemoveTrustedRootCertificate(bool machineTrusted = false)
{ {
//currentUser\personal // currentUser\personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate); UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
if (!machineTrusted) if (!machineTrusted)
{ {
//currentUser\Root // currentUser\Root
UninstallCertificate(StoreName.Root, StoreLocation.CurrentUser, RootCertificate); UninstallCertificate(StoreName.Root, StoreLocation.CurrentUser, RootCertificate);
} }
else else
{ {
//current system // current system
UninstallCertificate(StoreName.My, StoreLocation.LocalMachine, RootCertificate); UninstallCertificate(StoreName.My, StoreLocation.LocalMachine, RootCertificate);
//this adds to both currentUser\Root & currentMachine\Root // this adds to both currentUser\Root & currentMachine\Root
UninstallCertificate(StoreName.Root, StoreLocation.LocalMachine, RootCertificate); UninstallCertificate(StoreName.Root, StoreLocation.LocalMachine, RootCertificate);
} }
} }
...@@ -839,7 +828,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -839,7 +828,7 @@ namespace Titanium.Web.Proxy.Network
return false; return false;
} }
//currentUser\Personal // currentUser\Personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate); UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
var infos = new List<ProcessStartInfo>(); var infos = new List<ProcessStartInfo>();
...@@ -861,7 +850,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -861,7 +850,7 @@ namespace Titanium.Web.Proxy.Network
infos.AddRange( infos.AddRange(
new List<ProcessStartInfo> new List<ProcessStartInfo>
{ {
//currentMachine\Personal // currentMachine\Personal
new ProcessStartInfo new ProcessStartInfo
{ {
FileName = "certutil.exe", FileName = "certutil.exe",
...@@ -872,7 +861,8 @@ namespace Titanium.Web.Proxy.Network ...@@ -872,7 +861,8 @@ namespace Titanium.Web.Proxy.Network
ErrorDialog = false, ErrorDialog = false,
WindowStyle = ProcessWindowStyle.Hidden WindowStyle = ProcessWindowStyle.Hidden
}, },
//currentUser\Personal & currentMachine\Personal
// currentUser\Personal & currentMachine\Personal
new ProcessStartInfo new ProcessStartInfo
{ {
FileName = "certutil.exe", FileName = "certutil.exe",
......
#if DEBUG #if DEBUG
using System;
using System.IO; using System.IO;
using System.Text;
using System.Threading; using System.Threading;
using StreamExtended.Network; using StreamExtended.Network;
...@@ -15,30 +17,54 @@ namespace Titanium.Web.Proxy.Network ...@@ -15,30 +17,54 @@ namespace Titanium.Web.Proxy.Network
private readonly FileStream fileStreamSent; private readonly FileStream fileStreamSent;
public DebugCustomBufferedStream(Stream baseStream, int bufferSize) : base(baseStream, bufferSize) public DebugCustomBufferedStream(Guid connectionId, string type, Stream baseStream, int bufferSize, bool leaveOpen = false) : base(baseStream, bufferSize, leaveOpen)
{ {
Counter = Interlocked.Increment(ref counter); Counter = Interlocked.Increment(ref counter);
fileStreamSent = new FileStream(Path.Combine(basePath, $"{Counter}_sent.dat"), FileMode.Create); fileStreamSent = new FileStream(Path.Combine(basePath, $"{connectionId}_{type}_{Counter}_sent.dat"), FileMode.Create);
fileStreamReceived = new FileStream(Path.Combine(basePath, $"{Counter}_received.dat"), FileMode.Create); fileStreamReceived = new FileStream(Path.Combine(basePath, $"{connectionId}_{type}_{Counter}_received.dat"), FileMode.Create);
} }
public int Counter { get; } public int Counter { get; }
protected override void OnDataSent(byte[] buffer, int offset, int count) protected override void OnDataWrite(byte[] buffer, int offset, int count)
{ {
fileStreamSent.Write(buffer, offset, count); fileStreamSent.Write(buffer, offset, count);
Flush();
} }
protected override void OnDataReceived(byte[] buffer, int offset, int count) protected override void OnDataRead(byte[] buffer, int offset, int count)
{ {
fileStreamReceived.Write(buffer, offset, count); fileStreamReceived.Write(buffer, offset, count);
Flush();
} }
public void LogException(Exception ex)
{
var data = Encoding.UTF8.GetBytes("EXCEPTION: " + ex);
fileStreamReceived.Write(data, 0, data.Length);
fileStreamReceived.Flush();
}
public override void Flush() public override void Flush()
{ {
fileStreamSent.Flush(true); fileStreamSent.Flush(true);
fileStreamReceived.Flush(true); fileStreamReceived.Flush(true);
base.Flush();
if (CanWrite)
{
base.Flush();
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Flush();
fileStreamSent.Dispose();
fileStreamReceived.Dispose();
}
base.Dispose(disposing);
} }
} }
} }
......
using System.Net.Sockets; using StreamExtended.Network;
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
...@@ -10,20 +10,15 @@ namespace Titanium.Web.Proxy.Network ...@@ -10,20 +10,15 @@ namespace Titanium.Web.Proxy.Network
internal class ProxyClient internal class ProxyClient
{ {
/// <summary> /// <summary>
/// TcpClient used to communicate with client /// TcpClient connection used to communicate with client
/// </summary> /// </summary>
internal TcpClient TcpClient { get; set; } internal TcpClientConnection ClientConnection { get; set; }
/// <summary> /// <summary>
/// Holds the stream to client /// Holds the stream to client
/// </summary> /// </summary>
internal CustomBufferedStream ClientStream { get; set; } internal CustomBufferedStream ClientStream { get; set; }
/// <summary>
/// Used to read line by line from client
/// </summary>
internal CustomBinaryReader ClientStreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write line by line to client /// Used to write line by line to client
/// </summary> /// </summary>
......
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Network.Tcp
{
/// <summary>
/// An object that holds TcpConnection to a particular server and port
/// </summary>
internal class TcpClientConnection : IDisposable
{
internal TcpClientConnection(ProxyServer proxyServer, TcpClient tcpClient)
{
this.tcpClient = tcpClient;
this.proxyServer = proxyServer;
this.proxyServer.UpdateClientConnectionCount(true);
}
private ProxyServer proxyServer { get; }
public Guid Id { get; } = Guid.NewGuid();
public EndPoint LocalEndPoint => tcpClient.Client.LocalEndPoint;
public EndPoint RemoteEndPoint => tcpClient.Client.RemoteEndPoint;
internal SslApplicationProtocol NegotiatedApplicationProtocol { get; set; }
private readonly TcpClient tcpClient;
public Stream GetStream()
{
return tcpClient.GetStream();
}
/// <summary>
/// Dispose.
/// </summary>
public void Dispose()
{
tcpClient.CloseSocket();
proxyServer.UpdateClientConnectionCount(false);
}
}
}
...@@ -23,55 +23,55 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -23,55 +23,55 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
/// <param name="remoteHostName"></param> /// <param name="remoteHostName"></param>
/// <param name="remotePort"></param> /// <param name="remotePort"></param>
/// <param name="applicationProtocols"></param>
/// <param name="httpVersion"></param> /// <param name="httpVersion"></param>
/// <param name="decryptSsl"></param> /// <param name="decryptSsl"></param>
/// <param name="applicationProtocols"></param>
/// <param name="isConnect"></param> /// <param name="isConnect"></param>
/// <param name="proxyServer"></param> /// <param name="proxyServer"></param>
/// <param name="upStreamEndPoint"></param> /// <param name="upStreamEndPoint"></param>
/// <param name="externalProxy"></param> /// <param name="externalProxy"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpConnection> CreateClient(string remoteHostName, int remotePort, internal async Task<TcpServerConnection> CreateClient(string remoteHostName, int remotePort,
List<SslApplicationProtocol> applicationProtocols, Version httpVersion, bool decryptSsl, bool isConnect, Version httpVersion, bool decryptSsl, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
bool useUpstreamProxy = false; bool useUpstreamProxy = false;
//check if external proxy is set for HTTP/HTTPS // check if external proxy is set for HTTP/HTTPS
if (externalProxy != null && if (externalProxy != null &&
!(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort)) !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
{ {
useUpstreamProxy = true; useUpstreamProxy = true;
//check if we need to ByPass // check if we need to ByPass
if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName)) if (externalProxy.BypassLocalhost && NetworkHelper.IsLocalIpAddress(remoteHostName))
{ {
useUpstreamProxy = false; useUpstreamProxy = false;
} }
} }
TcpClient client = null; TcpClient tcpClient = null;
CustomBufferedStream stream = null; CustomBufferedStream stream = null;
bool http2Supported = false; SslApplicationProtocol negotiatedApplicationProtocol = default;
try try
{ {
client = new TcpClient(upStreamEndPoint); tcpClient = new TcpClient(upStreamEndPoint);
//If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections // If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
if (useUpstreamProxy) if (useUpstreamProxy)
{ {
await client.ConnectAsync(externalProxy.HostName, externalProxy.Port); await tcpClient.ConnectAsync(externalProxy.HostName, externalProxy.Port);
} }
else else
{ {
await client.ConnectAsync(remoteHostName, remotePort); await tcpClient.ConnectAsync(remoteHostName, remotePort);
} }
stream = new CustomBufferedStream(client.GetStream(), proxyServer.BufferSize); stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferSize);
if (useUpstreamProxy && (isConnect || decryptSsl)) if (useUpstreamProxy && (isConnect || decryptSsl))
{ {
...@@ -93,20 +93,17 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -93,20 +93,17 @@ namespace Titanium.Web.Proxy.Network.Tcp
await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken); await writer.WriteRequestAsync(connectRequest, cancellationToken: cancellationToken);
using (var reader = new CustomBinaryReader(stream, proxyServer.BufferSize)) string httpStatus = await stream.ReadLineAsync(cancellationToken);
{
string httpStatus = await reader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out _, out int statusCode, out string statusDescription);
if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK") if (statusCode != 200 && !statusDescription.EqualsIgnoreCase("OK")
&& !statusDescription.EqualsIgnoreCase("Connection Established")) && !statusDescription.EqualsIgnoreCase("Connection Established"))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
}
await reader.ReadAndIgnoreAllLinesAsync(cancellationToken);
} }
await stream.ReadAndIgnoreAllLinesAsync(cancellationToken);
} }
if (decryptSsl) if (decryptSsl)
...@@ -117,42 +114,35 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -117,42 +114,35 @@ namespace Titanium.Web.Proxy.Network.Tcp
var options = new SslClientAuthenticationOptions(); var options = new SslClientAuthenticationOptions();
options.ApplicationProtocols = applicationProtocols; options.ApplicationProtocols = applicationProtocols;
if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
{
options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
}
options.TargetHost = remoteHostName; options.TargetHost = remoteHostName;
options.ClientCertificates = null; options.ClientCertificates = null;
options.EnabledSslProtocols = proxyServer.SupportedSslProtocols; options.EnabledSslProtocols = proxyServer.SupportedSslProtocols;
options.CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation; options.CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation;
await sslStream.AuthenticateAsClientAsync(options, cancellationToken); await sslStream.AuthenticateAsClientAsync(options, cancellationToken);
#if NETCOREAPP2_1 #if NETCOREAPP2_1
http2Supported = sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif #endif
} }
client.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000; tcpClient.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
client.SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000; tcpClient.SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
} }
catch (Exception) catch (Exception)
{ {
stream?.Dispose(); stream?.Dispose();
client?.Close(); tcpClient?.Close();
throw; throw;
} }
return new TcpConnection(proxyServer) return new TcpServerConnection(proxyServer, tcpClient)
{ {
UpStreamProxy = externalProxy, UpStreamProxy = externalProxy,
UpStreamEndPoint = upStreamEndPoint, UpStreamEndPoint = upStreamEndPoint,
HostName = remoteHostName, HostName = remoteHostName,
Port = remotePort, Port = remotePort,
IsHttps = decryptSsl, IsHttps = decryptSsl,
IsHttp2Supported = http2Supported, NegotiatedApplicationProtocol = negotiatedApplicationProtocol,
UseUpstreamProxy = useUpstreamProxy, UseUpstreamProxy = useUpstreamProxy,
TcpClient = client,
StreamReader = new CustomBinaryReader(stream, proxyServer.BufferSize),
StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferSize), StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferSize),
Stream = stream, Stream = stream,
Version = httpVersion Version = httpVersion
......
using System; using System;
using System.Net; using System.Net;
using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -11,10 +12,11 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -11,10 +12,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <summary> /// <summary>
/// An object that holds TcpConnection to a particular server and port /// An object that holds TcpConnection to a particular server and port
/// </summary> /// </summary>
internal class TcpConnection : IDisposable internal class TcpServerConnection : IDisposable
{ {
internal TcpConnection(ProxyServer proxyServer) internal TcpServerConnection(ProxyServer proxyServer, TcpClient tcpClient)
{ {
this.tcpClient = tcpClient;
LastAccess = DateTime.Now; LastAccess = DateTime.Now;
this.proxyServer = proxyServer; this.proxyServer = proxyServer;
this.proxyServer.UpdateServerConnectionCount(true); this.proxyServer.UpdateServerConnectionCount(true);
...@@ -30,7 +32,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -30,7 +32,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal bool IsHttps { get; set; } internal bool IsHttps { get; set; }
internal bool IsHttp2Supported { get; set; } internal SslApplicationProtocol NegotiatedApplicationProtocol { get; set; }
internal bool UseUpstreamProxy { get; set; } internal bool UseUpstreamProxy { get; set; }
...@@ -44,12 +46,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -44,12 +46,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
internal Version Version { get; set; } internal Version Version { get; set; }
internal TcpClient TcpClient { private get; set; } private readonly TcpClient tcpClient;
/// <summary>
/// Used to read lines from server
/// </summary>
internal CustomBinaryReader StreamReader { get; set; }
/// <summary> /// <summary>
/// Used to write lines to server /// Used to write lines to server
...@@ -71,11 +68,9 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -71,11 +68,9 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
StreamReader?.Dispose();
Stream?.Dispose(); Stream?.Dispose();
TcpClient.CloseSocket(); tcpClient.CloseSocket();
proxyServer.UpdateServerConnectionCount(false); proxyServer.UpdateServerConnectionCount(false);
} }
......
...@@ -173,7 +173,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -173,7 +173,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
internal int ulVersion; internal int ulVersion;
internal int cBuffers; internal int cBuffers;
internal IntPtr pBuffers; //Point to SecBuffer internal IntPtr pBuffers; // Point to SecBuffer
internal SecurityBufferDesciption(int bufferSize) internal SecurityBufferDesciption(int bufferSize)
{ {
...@@ -206,12 +206,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -206,12 +206,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
for (int index = 0; index < cBuffers; index++) for (int index = 0; index < cBuffers; index++)
{ {
//The bits were written out the following order: // The bits were written out the following order:
//int cbBuffer; // int cbBuffer;
//int BufferType; // int BufferType;
//pvBuffer; // pvBuffer;
//What we need to do here is to grab a hold of the pvBuffer allocate by the individual //What we need to do here is to grab a hold of the pvBuffer allocate by the individual
//SecBuffer and release it... // SecBuffer and release it...
int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); int currentOffset = index * Marshal.SizeOf(typeof(Buffer));
var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,
currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int))); currentOffset + Marshal.SizeOf(typeof(int)) + Marshal.SizeOf(typeof(int)));
...@@ -249,11 +249,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -249,11 +249,11 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
for (int index = 0; index < cBuffers; index++) for (int index = 0; index < cBuffers; index++)
{ {
//The bits were written out the following order: // The bits were written out the following order:
//int cbBuffer; // int cbBuffer;
//int BufferType; // int BufferType;
//pvBuffer; // pvBuffer;
//What we need to do here calculate the total number of bytes we need to copy... // What we need to do here calculate the total number of bytes we need to copy...
int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); int currentOffset = index * Marshal.SizeOf(typeof(Buffer));
bytesToAllocate += Marshal.ReadInt32(pBuffers, currentOffset); bytesToAllocate += Marshal.ReadInt32(pBuffers, currentOffset);
} }
...@@ -262,12 +262,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -262,12 +262,12 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
for (int index = 0, bufferIndex = 0; index < cBuffers; index++) for (int index = 0, bufferIndex = 0; index < cBuffers; index++)
{ {
//The bits were written out the following order: // The bits were written out the following order:
//int cbBuffer; // int cbBuffer;
//int BufferType; // int BufferType;
//pvBuffer; // pvBuffer;
//Now iterate over the individual buffers and put them together into a // Now iterate over the individual buffers and put them together into a
//byte array... // byte array...
int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); int currentOffset = index * Marshal.SizeOf(typeof(Buffer));
int bytesToCopy = Marshal.ReadInt32(pBuffers, currentOffset); int bytesToCopy = Marshal.ReadInt32(pBuffers, currentOffset);
var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,
......
...@@ -65,29 +65,27 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -65,29 +65,27 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
// methods // methods
private void Decode(byte[] message) private void Decode(byte[] message)
{ {
//base.Decode (message);
if (message == null) if (message == null)
{ {
throw new ArgumentNullException("message"); throw new ArgumentNullException(nameof(message));
} }
if (message.Length < 12) if (message.Length < 12)
{ {
string msg = "Minimum Type3 message length is 12 bytes."; string msg = "Minimum Type3 message length is 12 bytes.";
throw new ArgumentOutOfRangeException("message", message.Length, msg); throw new ArgumentOutOfRangeException(nameof(message), message.Length, msg);
} }
if (!CheckHeader(message)) if (!CheckHeader(message))
{ {
string msg = "Invalid Type3 message header."; string msg = "Invalid Type3 message header.";
throw new ArgumentException(msg, "message"); throw new ArgumentException(msg, nameof(message));
} }
if (LittleEndian.ToUInt16(message, 56) != message.Length) if (LittleEndian.ToUInt16(message, 56) != message.Length)
{ {
string msg = "Invalid Type3 message length."; string msg = "Invalid Type3 message length.";
throw new ArgumentException(msg, "message"); throw new ArgumentException(msg, nameof(message));
} }
if (message.Length >= 64) if (message.Length >= 64)
......
...@@ -7,6 +7,7 @@ using System.Linq; ...@@ -7,6 +7,7 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Network.WinAuth.Security namespace Titanium.Web.Proxy.Network.WinAuth.Security
{ {
...@@ -14,24 +15,20 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -14,24 +15,20 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
internal class WinAuthEndPoint internal class WinAuthEndPoint
{ {
/// <summary> private const string authStateKey = "AuthState";
/// Keep track of auth states for reuse in final challenge response
/// </summary>
private static readonly IDictionary<Guid, State> authStates = new ConcurrentDictionary<Guid, State>();
/// <summary> /// <summary>
/// Acquire the intial client token to send /// Acquire the intial client token to send
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <param name="authScheme"></param> /// <param name="authScheme"></param>
/// <param name="requestId"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static byte[] AcquireInitialSecurityToken(string hostname, string authScheme, Guid requestId) internal static byte[] AcquireInitialSecurityToken(string hostname, string authScheme, InternalDataStore data)
{ {
byte[] token; byte[] token;
//null for initial call // null for initial call
var serverToken = new SecurityBufferDesciption(); var serverToken = new SecurityBufferDesciption();
var clientToken = new SecurityBufferDesciption(MaximumTokenSize); var clientToken = new SecurityBufferDesciption(MaximumTokenSize);
...@@ -68,8 +65,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -68,8 +65,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
out clientToken, out clientToken,
out NewContextAttributes, out NewContextAttributes,
out NewLifeTime); out NewLifeTime);
if (result != IntermediateResult) if (result != IntermediateResult)
{ {
return null; return null;
...@@ -77,7 +73,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -77,7 +73,7 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
state.AuthState = State.WinAuthState.INITIAL_TOKEN; state.AuthState = State.WinAuthState.INITIAL_TOKEN;
token = clientToken.GetBytes(); token = clientToken.GetBytes();
authStates.Add(requestId, state); data.Add(authStateKey, state);
} }
finally finally
{ {
...@@ -93,20 +89,20 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -93,20 +89,20 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <param name="serverChallenge"></param> /// <param name="serverChallenge"></param>
/// <param name="requestId"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static byte[] AcquireFinalSecurityToken(string hostname, byte[] serverChallenge, Guid requestId) internal static byte[] AcquireFinalSecurityToken(string hostname, byte[] serverChallenge, InternalDataStore data)
{ {
byte[] token; byte[] token;
//user server challenge // user server challenge
var serverToken = new SecurityBufferDesciption(serverChallenge); var serverToken = new SecurityBufferDesciption(serverChallenge);
var clientToken = new SecurityBufferDesciption(MaximumTokenSize); var clientToken = new SecurityBufferDesciption(MaximumTokenSize);
try try
{ {
var state = authStates[requestId]; var state = data.GetAs<State>(authStateKey);
state.UpdatePresence(); state.UpdatePresence();
...@@ -123,7 +119,6 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -123,7 +119,6 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
out NewContextAttributes, out NewContextAttributes,
out NewLifeTime); out NewLifeTime);
if (result != SuccessfulResult) if (result != SuccessfulResult)
{ {
return null; return null;
...@@ -141,50 +136,29 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -141,50 +136,29 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
return token; return token;
} }
/// <summary>
/// Clear any hanging states
/// </summary>
/// <param name="stateCacheTimeOutMinutes"></param>
internal static async void ClearIdleStates(int stateCacheTimeOutMinutes)
{
var cutOff = DateTime.Now.AddMinutes(-1 * stateCacheTimeOutMinutes);
var outdated = authStates.Where(x => x.Value.LastSeen < cutOff).ToList();
foreach (var cache in outdated)
{
authStates.Remove(cache.Key);
}
//after a minute come back to check for outdated certificates in cache
await Task.Delay(1000 * 60);
}
/// <summary> /// <summary>
/// Validates that the current WinAuth state of the connection matches the /// Validates that the current WinAuth state of the connection matches the
/// expectation, used to detect failed authentication /// expectation, used to detect failed authentication
/// </summary> /// </summary>
/// <param name="requestId"></param> /// <param name="data"></param>
/// <param name="expectedAuthState"></param> /// <param name="expectedAuthState"></param>
/// <returns></returns> /// <returns></returns>
internal static bool ValidateWinAuthState(Guid requestId, State.WinAuthState expectedAuthState) internal static bool ValidateWinAuthState(InternalDataStore data, State.WinAuthState expectedAuthState)
{ {
bool stateExists = authStates.TryGetValue(requestId, out var state); bool stateExists = data.TryGetValueAs(authStateKey, out State state);
if (expectedAuthState == State.WinAuthState.UNAUTHORIZED) if (expectedAuthState == State.WinAuthState.UNAUTHORIZED)
{ {
return stateExists == false || return !stateExists ||
state.AuthState == State.WinAuthState.UNAUTHORIZED || state.AuthState == State.WinAuthState.UNAUTHORIZED ||
state.AuthState == state.AuthState == State.WinAuthState.AUTHORIZED; // Server may require re-authentication on an open connection
State.WinAuthState.AUTHORIZED; // Server may require re-authentication on an open connection
} }
if (expectedAuthState == State.WinAuthState.INITIAL_TOKEN) if (expectedAuthState == State.WinAuthState.INITIAL_TOKEN)
{ {
return stateExists && return stateExists &&
(state.AuthState == State.WinAuthState.INITIAL_TOKEN || (state.AuthState == State.WinAuthState.INITIAL_TOKEN ||
state.AuthState == State.WinAuthState.AUTHORIZED state.AuthState == State.WinAuthState.AUTHORIZED); // Server may require re-authentication on an open connection
); // Server may require re-authentication on an open connection
} }
throw new Exception("Unsupported validation of WinAuthState"); throw new Exception("Unsupported validation of WinAuthState");
...@@ -193,10 +167,10 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -193,10 +167,10 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
/// <summary> /// <summary>
/// Set the AuthState to authorized and update the connection state lifetime /// Set the AuthState to authorized and update the connection state lifetime
/// </summary> /// </summary>
/// <param name="requestId"></param> /// <param name="data"></param>
internal static void AuthenticatedResponse(Guid requestId) internal static void AuthenticatedResponse(InternalDataStore data)
{ {
if (authStates.TryGetValue(requestId, out var state)) if (data.TryGetValueAs(authStateKey, out State state))
{ {
state.AuthState = State.WinAuthState.AUTHORIZED; state.AuthState = State.WinAuthState.AUTHORIZED;
state.UpdatePresence(); state.UpdatePresence();
...@@ -206,44 +180,44 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security ...@@ -206,44 +180,44 @@ namespace Titanium.Web.Proxy.Network.WinAuth.Security
#region Native calls to secur32.dll #region Native calls to secur32.dll
[DllImport("secur32.dll", SetLastError = true)] [DllImport("secur32.dll", SetLastError = true)]
private static extern int InitializeSecurityContext(ref SecurityHandle phCredential, //PCredHandle private static extern int InitializeSecurityContext(ref SecurityHandle phCredential, // PCredHandle
IntPtr phContext, //PCtxtHandle IntPtr phContext, // PCtxtHandle
string pszTargetName, string pszTargetName,
int fContextReq, int fContextReq,
int reserved1, int reserved1,
int targetDataRep, int targetDataRep,
ref SecurityBufferDesciption pInput, //PSecBufferDesc SecBufferDesc ref SecurityBufferDesciption pInput, // PSecBufferDesc SecBufferDesc
int reserved2, int reserved2,
out SecurityHandle phNewContext, //PCtxtHandle out SecurityHandle phNewContext, // PCtxtHandle
out SecurityBufferDesciption pOutput, //PSecBufferDesc SecBufferDesc out SecurityBufferDesciption pOutput, // PSecBufferDesc SecBufferDesc
out uint pfContextAttr, //managed ulong == 64 bits!!! out uint pfContextAttr, // managed ulong == 64 bits!!!
out SecurityInteger ptsExpiry); //PTimeStamp out SecurityInteger ptsExpiry); // PTimeStamp
[DllImport("secur32", CharSet = CharSet.Auto, SetLastError = true)] [DllImport("secur32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int InitializeSecurityContext(ref SecurityHandle phCredential, //PCredHandle private static extern int InitializeSecurityContext(ref SecurityHandle phCredential, // PCredHandle
ref SecurityHandle phContext, //PCtxtHandle ref SecurityHandle phContext, // PCtxtHandle
string pszTargetName, string pszTargetName,
int fContextReq, int fContextReq,
int reserved1, int reserved1,
int targetDataRep, int targetDataRep,
ref SecurityBufferDesciption secBufferDesc, //PSecBufferDesc SecBufferDesc ref SecurityBufferDesciption secBufferDesc, // PSecBufferDesc SecBufferDesc
int reserved2, int reserved2,
out SecurityHandle phNewContext, //PCtxtHandle out SecurityHandle phNewContext, // PCtxtHandle
out SecurityBufferDesciption pOutput, //PSecBufferDesc SecBufferDesc out SecurityBufferDesciption pOutput, // PSecBufferDesc SecBufferDesc
out uint pfContextAttr, //managed ulong == 64 bits!!! out uint pfContextAttr, // managed ulong == 64 bits!!!
out SecurityInteger ptsExpiry); //PTimeStamp out SecurityInteger ptsExpiry); // PTimeStamp
[DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = false)] [DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern int AcquireCredentialsHandle( private static extern int AcquireCredentialsHandle(
string pszPrincipal, //SEC_CHAR* string pszPrincipal, // SEC_CHAR*
string pszPackage, //SEC_CHAR* //"Kerberos","NTLM","Negotiative" string pszPackage, // SEC_CHAR* // "Kerberos","NTLM","Negotiative"
int fCredentialUse, int fCredentialUse,
IntPtr pAuthenticationId, //_LUID AuthenticationID,//pvLogonID, //PLUID IntPtr pAuthenticationId, // _LUID AuthenticationID,//pvLogonID, // PLUID
IntPtr pAuthData, //PVOID IntPtr pAuthData, // PVOID
int pGetKeyFn, //SEC_GET_KEY_FN int pGetKeyFn, // SEC_GET_KEY_FN
IntPtr pvGetKeyArgument, //PVOID IntPtr pvGetKeyArgument, // PVOID
ref SecurityHandle phCredential, //SecHandle //PCtxtHandle ref ref SecurityHandle phCredential, // SecHandle // PCtxtHandle ref
ref SecurityInteger ptsExpiry); //PTimeStamp //TimeStamp ref ref SecurityInteger ptsExpiry); // PTimeStamp // TimeStamp ref
#endregion #endregion
} }
......
using System; using System;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Network.WinAuth.Security; using Titanium.Web.Proxy.Network.WinAuth.Security;
namespace Titanium.Web.Proxy.Network.WinAuth namespace Titanium.Web.Proxy.Network.WinAuth
...@@ -16,27 +17,26 @@ namespace Titanium.Web.Proxy.Network.WinAuth ...@@ -16,27 +17,26 @@ namespace Titanium.Web.Proxy.Network.WinAuth
/// </summary> /// </summary>
/// <param name="serverHostname"></param> /// <param name="serverHostname"></param>
/// <param name="authScheme"></param> /// <param name="authScheme"></param>
/// <param name="requestId"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static string GetInitialAuthToken(string serverHostname, string authScheme, Guid requestId) internal static string GetInitialAuthToken(string serverHostname, string authScheme, InternalDataStore data)
{ {
var tokenBytes = WinAuthEndPoint.AcquireInitialSecurityToken(serverHostname, authScheme, requestId); var tokenBytes = WinAuthEndPoint.AcquireInitialSecurityToken(serverHostname, authScheme, data);
return string.Concat(" ", Convert.ToBase64String(tokenBytes)); return string.Concat(" ", Convert.ToBase64String(tokenBytes));
} }
/// <summary> /// <summary>
/// Get the final token given the server challenge token /// Get the final token given the server challenge token
/// </summary> /// </summary>
/// <param name="serverHostname"></param> /// <param name="serverHostname"></param>
/// <param name="serverToken"></param> /// <param name="serverToken"></param>
/// <param name="requestId"></param> /// <param name="data"></param>
/// <returns></returns> /// <returns></returns>
internal static string GetFinalAuthToken(string serverHostname, string serverToken, Guid requestId) internal static string GetFinalAuthToken(string serverHostname, string serverToken, InternalDataStore data)
{ {
var tokenBytes = var tokenBytes =
WinAuthEndPoint.AcquireFinalSecurityToken(serverHostname, Convert.FromBase64String(serverToken), WinAuthEndPoint.AcquireFinalSecurityToken(serverHostname, Convert.FromBase64String(serverToken),
requestId); data);
return string.Concat(" ", Convert.ToBase64String(tokenBytes)); return string.Concat(" ", Convert.ToBase64String(tokenBytes));
} }
......
...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy ...@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy
/// <returns>True if authorized.</returns> /// <returns>True if authorized.</returns>
private async Task<bool> CheckAuthorization(SessionEventArgsBase session) private async Task<bool> CheckAuthorization(SessionEventArgsBase session)
{ {
//If we are not authorizing clients return true // If we are not authorizing clients return true
if (AuthenticateUserFunc == null) if (AuthenticateUserFunc == null)
{ {
return true; return true;
...@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy ...@@ -41,7 +41,7 @@ namespace Titanium.Web.Proxy
if (headerValueParts.Length != 2 || if (headerValueParts.Length != 2 ||
!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
{ {
//Return not authorized // Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy ...@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy
int colonIndex = decoded.IndexOf(':'); int colonIndex = decoded.IndexOf(':');
if (colonIndex == -1) if (colonIndex == -1)
{ {
//Return not authorized // Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy ...@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy
ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e,
httpHeaders)); httpHeaders));
//Return not authorized // Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
......
...@@ -7,6 +7,7 @@ using System.Security.Authentication; ...@@ -7,6 +7,7 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
...@@ -18,17 +19,17 @@ using Titanium.Web.Proxy.Network.WinAuth.Security; ...@@ -18,17 +19,17 @@ using Titanium.Web.Proxy.Network.WinAuth.Security;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
/// <inheritdoc />
/// <summary> /// <summary>
/// This object is the backbone of proxy. One can create as many instances as needed. /// 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. /// However care should be taken to avoid using the same listening ports across multiple instances.
/// </summary> /// </summary>
public partial class ProxyServer : IDisposable public partial class ProxyServer : IDisposable
{ {
/// <summary> /// <summary>
/// HTTP & HTTPS scheme shorthands. /// HTTP &amp; HTTPS scheme shorthands.
/// </summary> /// </summary>
internal static readonly string UriSchemeHttp = Uri.UriSchemeHttp; internal static readonly string UriSchemeHttp = Uri.UriSchemeHttp;
internal static readonly string UriSchemeHttps = Uri.UriSchemeHttps; internal static readonly string UriSchemeHttps = Uri.UriSchemeHttps;
/// <summary> /// <summary>
...@@ -56,6 +57,7 @@ namespace Titanium.Web.Proxy ...@@ -56,6 +57,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
private WinHttpWebProxyFinder systemProxyResolver; private WinHttpWebProxyFinder systemProxyResolver;
/// <inheritdoc />
/// <summary> /// <summary>
/// Initializes a new instance of ProxyServer class with provided parameters. /// Initializes a new instance of ProxyServer class with provided parameters.
/// </summary> /// </summary>
...@@ -92,8 +94,8 @@ namespace Titanium.Web.Proxy ...@@ -92,8 +94,8 @@ namespace Titanium.Web.Proxy
bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false,
bool trustRootCertificateAsAdmin = false) bool trustRootCertificateAsAdmin = false)
{ {
//default values // default values
ConnectionTimeOutSeconds = 30; ConnectionTimeOutSeconds = 60;
ProxyEndPoints = new List<ProxyEndPoint>(); ProxyEndPoints = new List<ProxyEndPoint>();
tcpConnectionFactory = new TcpConnectionFactory(); tcpConnectionFactory = new TcpConnectionFactory();
...@@ -107,7 +109,7 @@ namespace Titanium.Web.Proxy ...@@ -107,7 +109,7 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// An object that creates tcp connection to server. /// An factory that creates tcp connection to server.
/// </summary> /// </summary>
private TcpConnectionFactory tcpConnectionFactory { get; } private TcpConnectionFactory tcpConnectionFactory { get; }
...@@ -127,7 +129,7 @@ namespace Titanium.Web.Proxy ...@@ -127,7 +129,7 @@ namespace Titanium.Web.Proxy
public bool ForwardToUpstreamGateway { get; set; } public bool ForwardToUpstreamGateway { get; set; }
/// <summary> /// <summary>
/// Enable disable Windows Authentication (NTLM/Kerberos) /// Enable disable Windows Authentication (NTLM/Kerberos).
/// Note: NTLM/Kerberos will always send local credentials of current user /// Note: NTLM/Kerberos will always send local credentials of current user
/// running the proxy process. This is because a man /// running the proxy process. This is because a man
/// in middle attack with Windows domain authentication is not currently supported. /// in middle attack with Windows domain authentication is not currently supported.
...@@ -143,6 +145,7 @@ namespace Titanium.Web.Proxy ...@@ -143,6 +145,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly? /// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 contunue implementations on server/client may cause problems if enabled. /// Broken 100 contunue implementations on server/client may cause problems if enabled.
/// Defaults to false.
/// </summary> /// </summary>
public bool Enable100ContinueBehaviour { get; set; } public bool Enable100ContinueBehaviour { get; set; }
...@@ -170,8 +173,7 @@ namespace Titanium.Web.Proxy ...@@ -170,8 +173,7 @@ namespace Titanium.Web.Proxy
/// Realm used during Proxy Basic Authentication. /// Realm used during Proxy Basic Authentication.
/// </summary> /// </summary>
public string ProxyRealm { get; set; } = "TitaniumProxy"; public string ProxyRealm { get; set; } = "TitaniumProxy";
/// <summary> /// <summary>
/// List of supported Ssl versions. /// List of supported Ssl versions.
/// </summary> /// </summary>
...@@ -181,7 +183,6 @@ namespace Titanium.Web.Proxy ...@@ -181,7 +183,6 @@ namespace Titanium.Web.Proxy
#endif #endif
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
/// <summary> /// <summary>
/// Manages certificates used by this proxy. /// Manages certificates used by this proxy.
/// </summary> /// </summary>
...@@ -226,12 +227,12 @@ namespace Titanium.Web.Proxy ...@@ -226,12 +227,12 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// A callback to authenticate clients. /// A callback to authenticate clients.
/// Parameters are username and password as provided by client. /// Parameters are username and password as provided by client.
/// Return true for successful authentication. /// Should return true for successful authentication.
/// </summary> /// </summary>
public Func<string, string, Task<bool>> AuthenticateUserFunc { get; set; } public Func<string, string, Task<bool>> AuthenticateUserFunc { get; set; }
/// <summary> /// <summary>
/// Dispose Proxy. /// Dispose the Proxy instance.
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
...@@ -244,37 +245,37 @@ namespace Titanium.Web.Proxy ...@@ -244,37 +245,37 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// Occurs when client connection count changed. /// Event occurs when client connection count changed.
/// </summary> /// </summary>
public event EventHandler ClientConnectionCountChanged; public event EventHandler ClientConnectionCountChanged;
/// <summary> /// <summary>
/// Occurs when server connection count changed. /// Event occurs when server connection count changed.
/// </summary> /// </summary>
public event EventHandler ServerConnectionCountChanged; public event EventHandler ServerConnectionCountChanged;
/// <summary> /// <summary>
/// Verifies the remote SSL certificate used for authentication. /// Event to override the default verification logic of remote SSL certificate received during authentication.
/// </summary> /// </summary>
public event AsyncEventHandler<CertificateValidationEventArgs> ServerCertificateValidationCallback; public event AsyncEventHandler<CertificateValidationEventArgs> ServerCertificateValidationCallback;
/// <summary> /// <summary>
/// Callback to override client certificate selection during mutual SSL authentication. /// Event to override client certificate selection during mutual SSL authentication.
/// </summary> /// </summary>
public event AsyncEventHandler<CertificateSelectionEventArgs> ClientCertificateSelectionCallback; public event AsyncEventHandler<CertificateSelectionEventArgs> ClientCertificateSelectionCallback;
/// <summary> /// <summary>
/// Intercept request to server. /// Intercept request event to server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> BeforeRequest; public event AsyncEventHandler<SessionEventArgs> BeforeRequest;
/// <summary> /// <summary>
/// Intercept response from server. /// Intercept response event from server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> BeforeResponse; public event AsyncEventHandler<SessionEventArgs> BeforeResponse;
/// <summary> /// <summary>
/// Intercept after response from server. /// Intercept after response event from server.
/// </summary> /// </summary>
public event AsyncEventHandler<SessionEventArgs> AfterResponse; public event AsyncEventHandler<SessionEventArgs> AfterResponse;
...@@ -300,7 +301,7 @@ namespace Titanium.Web.Proxy ...@@ -300,7 +301,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Remove a proxy end point. /// Remove a proxy end point.
/// Will throw error if the end point does'nt exist /// Will throw error if the end point does'nt exist.
/// </summary> /// </summary>
/// <param name="endPoint">The existing endpoint to remove.</param> /// <param name="endPoint">The existing endpoint to remove.</param>
public void RemoveEndPoint(ProxyEndPoint endPoint) public void RemoveEndPoint(ProxyEndPoint endPoint)
...@@ -321,7 +322,7 @@ namespace Titanium.Web.Proxy ...@@ -321,7 +322,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Set the given explicit end point as the default proxy server for current machine. /// Set the given explicit end point as the default proxy server for current machine.
/// </summary> /// </summary>
/// <param name="endPoint"></param> /// <param name="endPoint">The explicit endpoint.</param>
public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint)
{ {
SetAsSystemProxy(endPoint, ProxyProtocolType.Http); SetAsSystemProxy(endPoint, ProxyProtocolType.Http);
...@@ -330,7 +331,7 @@ namespace Titanium.Web.Proxy ...@@ -330,7 +331,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Set the given explicit end point as the default proxy server for current machine. /// Set the given explicit end point as the default proxy server for current machine.
/// </summary> /// </summary>
/// <param name="endPoint"></param> /// <param name="endPoint">The explicit endpoint.</param>
public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint)
{ {
SetAsSystemProxy(endPoint, ProxyProtocolType.Https); SetAsSystemProxy(endPoint, ProxyProtocolType.Https);
...@@ -339,8 +340,8 @@ namespace Titanium.Web.Proxy ...@@ -339,8 +340,8 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Set the given explicit end point as the default proxy server for current machine. /// Set the given explicit end point as the default proxy server for current machine.
/// </summary> /// </summary>
/// <param name="endPoint"></param> /// <param name="endPoint">The explicit endpoint.</param>
/// <param name="protocolType"></param> /// <param name="protocolType">The proxy protocol type.</param>
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType)
{ {
if (RunTime.IsRunningOnMono) if (RunTime.IsRunningOnMono)
...@@ -357,7 +358,7 @@ namespace Titanium.Web.Proxy ...@@ -357,7 +358,7 @@ namespace Titanium.Web.Proxy
{ {
CertificateManager.EnsureRootCertificate(); CertificateManager.EnsureRootCertificate();
//If certificate was trusted by the machine // If certificate was trusted by the machine
if (!CertificateManager.CertValidated) if (!CertificateManager.CertValidated)
{ {
protocolType = protocolType & ~ProxyProtocolType.Https; protocolType = protocolType & ~ProxyProtocolType.Https;
...@@ -365,7 +366,7 @@ namespace Titanium.Web.Proxy ...@@ -365,7 +366,7 @@ namespace Titanium.Web.Proxy
} }
} }
//clear any settings previously added // clear any settings previously added
if (isHttp) if (isHttp)
{ {
ProxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false); ProxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false);
...@@ -472,8 +473,8 @@ namespace Titanium.Web.Proxy ...@@ -472,8 +473,8 @@ namespace Titanium.Web.Proxy
CertificateManager.EnsureRootCertificate(); CertificateManager.EnsureRootCertificate();
} }
//clear any system proxy settings which is pointing to our own endpoint (causing a cycle) // clear any system proxy settings which is pointing to our own endpoint (causing a cycle)
//due to non gracious proxy shutdown before or something else // due to ungracious proxy shutdown before or something else
if (systemProxySettingsManager != null && RunTime.IsWindows) if (systemProxySettingsManager != null && RunTime.IsWindows)
{ {
var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry(); var proxyInfo = systemProxySettingsManager.GetProxyInfoFromRegistry();
...@@ -483,7 +484,7 @@ namespace Titanium.Web.Proxy ...@@ -483,7 +484,7 @@ namespace Titanium.Web.Proxy
foreach (var proxy in proxyInfo.Proxies.Values) foreach (var proxy in proxyInfo.Proxies.Values)
{ {
if ((proxy.HostName == "127.0.0.1" if ((proxy.HostName == "127.0.0.1"
|| proxy.HostName.Equals("localhost", StringComparison.OrdinalIgnoreCase)) || proxy.HostName.EqualsIgnoreCase("localhost"))
&& ProxyEndPoints.Any(x => x.Port == proxy.Port)) && ProxyEndPoints.Any(x => x.Port == proxy.Port))
{ {
protocolToRemove |= proxy.ProtocolType; protocolToRemove |= proxy.ProtocolType;
...@@ -508,16 +509,11 @@ namespace Titanium.Web.Proxy ...@@ -508,16 +509,11 @@ namespace Titanium.Web.Proxy
ProxyRunning = true; ProxyRunning = true;
foreach (var endPoint in ProxyEndPoints)
{
Listen(endPoint);
}
CertificateManager.ClearIdleCertificates(); CertificateManager.ClearIdleCertificates();
if (RunTime.IsWindows && !RunTime.IsRunningOnMono) foreach (var endPoint in ProxyEndPoints)
{ {
WinAuthEndPoint.ClearIdleStates(2); Listen(endPoint);
} }
} }
...@@ -603,8 +599,10 @@ namespace Titanium.Web.Proxy ...@@ -603,8 +599,10 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// Gets the system up stream proxy. /// Gets the system up stream proxy.
/// </summary> /// </summary>
/// <param name="sessionEventArgs">The session.</param>
/// <returns>The external proxy as task result.</returns>
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgsBase sessionEventArgs) private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgsBase sessionEventArgs)
{ {
var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri); var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri);
...@@ -622,7 +620,7 @@ namespace Titanium.Web.Proxy ...@@ -622,7 +620,7 @@ namespace Titanium.Web.Proxy
try try
{ {
//based on end point type call appropriate request handlers // based on end point type call appropriate request handlers
tcpClient = endPoint.Listener.EndAcceptTcpClient(asyn); tcpClient = endPoint.Listener.EndAcceptTcpClient(asyn);
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
...@@ -634,7 +632,7 @@ namespace Titanium.Web.Proxy ...@@ -634,7 +632,7 @@ namespace Titanium.Web.Proxy
} }
catch catch
{ {
//Other errors are discarded to keep proxy running // Other errors are discarded to keep proxy running
} }
if (tcpClient != null) if (tcpClient != null)
...@@ -646,29 +644,45 @@ namespace Titanium.Web.Proxy ...@@ -646,29 +644,45 @@ namespace Titanium.Web.Proxy
endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint); endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
} }
/// <summary>
/// Handle the client.
/// </summary>
/// <param name="tcpClient">The client.</param>
/// <param name="endPoint">The proxy endpoint.</param>
/// <returns>The task.</returns>
private async Task HandleClient(TcpClient tcpClient, ProxyEndPoint endPoint) private async Task HandleClient(TcpClient tcpClient, ProxyEndPoint endPoint)
{ {
UpdateClientConnectionCount(true);
tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000; tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000;
try using (var clientConnection = new TcpClientConnection(this, tcpClient))
{ {
if (endPoint is TransparentProxyEndPoint tep) if (endPoint is TransparentProxyEndPoint tep)
{ {
await HandleClient(tep, tcpClient); await HandleClient(tep, clientConnection);
} }
else else
{ {
await HandleClient((ExplicitProxyEndPoint)endPoint, tcpClient); await HandleClient((ExplicitProxyEndPoint)endPoint, clientConnection);
} }
} }
finally }
/// <summary>
/// Handle exception.
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <param name="exception">The exception.</param>
private void OnException(CustomBufferedStream clientStream, Exception exception)
{
#if DEBUG
if (clientStream is DebugCustomBufferedStream debugStream)
{ {
UpdateClientConnectionCount(false); debugStream.LogException(exception);
tcpClient.CloseSocket();
} }
#endif
ExceptionFunc(exception);
} }
/// <summary> /// <summary>
...@@ -683,7 +697,7 @@ namespace Titanium.Web.Proxy ...@@ -683,7 +697,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Update client connection count. /// Update client connection count.
/// </summary> /// </summary>
/// <param name="increment"></param> /// <param name="increment">Should we increment/decrement?</param>
internal void UpdateClientConnectionCount(bool increment) internal void UpdateClientConnectionCount(bool increment)
{ {
if (increment) if (increment)
...@@ -701,7 +715,7 @@ namespace Titanium.Web.Proxy ...@@ -701,7 +715,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Update server connection count. /// Update server connection count.
/// </summary> /// </summary>
/// <param name="increment"></param> /// <param name="increment">Should we increment/decrement?</param>
internal void UpdateServerConnectionCount(bool increment) internal void UpdateServerConnectionCount(bool increment)
{ {
if (increment) if (increment)
......
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -18,23 +20,28 @@ namespace Titanium.Web.Proxy ...@@ -18,23 +20,28 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Handle the request /// Handle the request
/// </summary> /// </summary>
partial class ProxyServer public partial class ProxyServer
{ {
private static readonly Regex uriSchemeRegex = private static readonly Regex uriSchemeRegex =
new Regex("^[a-z]*://", RegexOptions.IgnoreCase | RegexOptions.Compiled); new Regex("^[a-z]*://", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly HashSet<string> proxySupportedCompressions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"gzip",
"deflate"
};
private bool isWindowsAuthenticationEnabledAndSupported => private bool isWindowsAuthenticationEnabledAndSupported =>
EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono; EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono;
/// <summary> /// <summary>
/// This is the core request handler method for a particular connection from client. /// This is the core request handler method for a particular connection from client.
/// Will create new session (request/response) sequence until /// Will create new session (request/response) sequence until
/// client/server abruptly terminates connection or by normal HTTP termination. /// client/server abruptly terminates connection or by normal HTTP termination.
/// </summary> /// </summary>
/// <param name="endPoint">The proxy endpoint.</param> /// <param name="endPoint">The proxy endpoint.</param>
/// <param name="client">The client.</param> /// <param name="clientConnection">The client connection.</param>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStream">The client stream.</param>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <param name="clientStreamWriter">The client stream writer.</param> /// <param name="clientStreamWriter">The client stream writer.</param>
/// <param name="cancellationTokenSource">The cancellation token source for this async task.</param> /// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
/// <param name="httpsConnectHostname"> /// <param name="httpsConnectHostname">
...@@ -42,25 +49,21 @@ namespace Titanium.Web.Proxy ...@@ -42,25 +49,21 @@ namespace Titanium.Web.Proxy
/// explicit endpoint. /// explicit endpoint.
/// </param> /// </param>
/// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param> /// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <param name="isTransparentEndPoint">Is this a request from transparent endpoint?</param> private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
/// <returns></returns> CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClient client, CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest)
CustomBufferedStream clientStream, CustomBinaryReader clientStreamReader,
HttpResponseWriter clientStreamWriter,
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest,
bool isTransparentEndPoint = false)
{ {
var cancellationToken = cancellationTokenSource.Token; var cancellationToken = cancellationTokenSource.Token;
TcpConnection connection = null; TcpServerConnection serverConnection = null;
try try
{ {
//Loop through each subsequest request on this particular client connection // Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client) // (assuming HTTP connection is kept alive by client)
while (true) while (true)
{ {
// read the request line // read the request line
string httpCmd = await clientStreamReader.ReadLineAsync(cancellationToken); string httpCmd = await clientStream.ReadLineAsync(cancellationToken);
if (string.IsNullOrEmpty(httpCmd)) if (string.IsNullOrEmpty(httpCmd))
{ {
...@@ -69,7 +72,7 @@ namespace Titanium.Web.Proxy ...@@ -69,7 +72,7 @@ namespace Titanium.Web.Proxy
var args = new SessionEventArgs(BufferSize, endPoint, cancellationTokenSource, ExceptionFunc) var args = new SessionEventArgs(BufferSize, endPoint, cancellationTokenSource, ExceptionFunc)
{ {
ProxyClient = { TcpClient = client }, ProxyClient = { ClientConnection = clientConnection },
WebSession = { ConnectRequest = connectRequest } WebSession = { ConnectRequest = connectRequest }
}; };
...@@ -80,8 +83,8 @@ namespace Titanium.Web.Proxy ...@@ -80,8 +83,8 @@ namespace Titanium.Web.Proxy
Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl, Request.ParseRequestLine(httpCmd, out string httpMethod, out string httpUrl,
out var version); out var version);
//Read the request headers in to unique and non-unique header collections // Read the request headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.Headers, await HeaderParser.ReadHeaders(clientStream, args.WebSession.Request.Headers,
cancellationToken); cancellationToken);
Uri httpRemoteUri; Uri httpRemoteUri;
...@@ -124,30 +127,28 @@ namespace Titanium.Web.Proxy ...@@ -124,30 +127,28 @@ namespace Titanium.Web.Proxy
request.Method = httpMethod; request.Method = httpMethod;
request.HttpVersion = version; request.HttpVersion = version;
args.ProxyClient.ClientStream = clientStream; args.ProxyClient.ClientStream = clientStream;
args.ProxyClient.ClientStreamReader = clientStreamReader;
args.ProxyClient.ClientStreamWriter = clientStreamWriter; args.ProxyClient.ClientStreamWriter = clientStreamWriter;
//proxy authorization check if (!args.IsTransparent)
if (!args.IsTransparent && httpsConnectHostname == null &&
await CheckAuthorization(args) == false)
{ {
await InvokeBeforeResponse(args); // proxy authorization check
if (httpsConnectHostname == null && await CheckAuthorization(args) == false)
{
await InvokeBeforeResponse(args);
//send the response // send the response
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response, await clientStreamWriter.WriteResponseAsync(args.WebSession.Response,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
return; return;
} }
if (!isTransparentEndPoint)
{
PrepareRequestHeaders(request.Headers); PrepareRequestHeaders(request.Headers);
request.Host = request.RequestUri.Authority; request.Host = request.RequestUri.Authority;
} }
//if win auth is enabled // if win auth is enabled
//we need a cache of request body // we need a cache of request body
//so that we can send it after authentication in WinAuthHandler.cs // so that we can send it after authentication in WinAuthHandler.cs
if (isWindowsAuthenticationEnabledAndSupported && request.HasBody) if (isWindowsAuthenticationEnabledAndSupported && request.HasBody)
{ {
await args.GetRequestBody(cancellationToken); await args.GetRequestBody(cancellationToken);
...@@ -155,14 +156,14 @@ namespace Titanium.Web.Proxy ...@@ -155,14 +156,14 @@ namespace Titanium.Web.Proxy
request.OriginalHasBody = request.HasBody; request.OriginalHasBody = request.HasBody;
//If user requested interception do it // If user requested interception do it
await InvokeBeforeRequest(args); await InvokeBeforeRequest(args);
var response = args.WebSession.Response; var response = args.WebSession.Response;
if (request.CancelRequest) if (request.CancelRequest)
{ {
//syphon out the request body from client before setting the new body // syphon out the request body from client before setting the new body
await args.SyphonOutBodyAsync(true, cancellationToken); await args.SyphonOutBodyAsync(true, cancellationToken);
await HandleHttpSessionResponse(args); await HandleHttpSessionResponse(args);
...@@ -175,30 +176,29 @@ namespace Titanium.Web.Proxy ...@@ -175,30 +176,29 @@ namespace Titanium.Web.Proxy
continue; continue;
} }
//create a new connection if hostname/upstream end point changes // create a new connection if hostname/upstream end point changes
if (connection != null if (serverConnection != null
&& (!connection.HostName.Equals(request.RequestUri.Host, && (!serverConnection.HostName.EqualsIgnoreCase(request.RequestUri.Host)
StringComparison.OrdinalIgnoreCase) || args.WebSession.UpStreamEndPoint?.Equals(serverConnection.UpStreamEndPoint) ==
|| args.WebSession.UpStreamEndPoint != null false))
&& !args.WebSession.UpStreamEndPoint.Equals(connection.UpStreamEndPoint)))
{ {
connection.Dispose(); serverConnection.Dispose();
connection = null; serverConnection = null;
} }
if (connection == null) if (serverConnection == null)
{ {
connection = await GetServerConnection(args, false, cancellationToken); serverConnection = await GetServerConnection(args, false, clientConnection.NegotiatedApplicationProtocol, cancellationToken);
} }
//if upgrading to websocket then relay the requet without reading the contents // if upgrading to websocket then relay the requet without reading the contents
if (request.UpgradeToWebSocket) if (request.UpgradeToWebSocket)
{ {
//prepare the prefix content // prepare the prefix content
await connection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken); await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await connection.StreamWriter.WriteHeadersAsync(request.Headers, await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
string httpStatus = await connection.StreamReader.ReadLineAsync(cancellationToken); string httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out var responseVersion, Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode, out int responseStatusCode,
...@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy ...@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy
response.StatusCode = responseStatusCode; response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription; response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(connection.StreamReader, response.Headers, await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
cancellationToken); cancellationToken);
if (!args.IsTransparent) if (!args.IsTransparent)
...@@ -216,13 +216,13 @@ namespace Titanium.Web.Proxy ...@@ -216,13 +216,13 @@ namespace Titanium.Web.Proxy
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
} }
//If user requested call back then do it // If user requested call back then do it
if (!args.WebSession.Response.Locked) if (!args.WebSession.Response.Locked)
{ {
await InvokeBeforeResponse(args); await InvokeBeforeResponse(args);
} }
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); }, (buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
cancellationTokenSource, ExceptionFunc); cancellationTokenSource, ExceptionFunc);
...@@ -230,15 +230,15 @@ namespace Titanium.Web.Proxy ...@@ -230,15 +230,15 @@ namespace Titanium.Web.Proxy
return; return;
} }
//construct the web request that we are going to issue on behalf of the client. // construct the web request that we are going to issue on behalf of the client.
await HandleHttpSessionRequestInternal(connection, args); await HandleHttpSessionRequestInternal(serverConnection, args);
if (args.WebSession.ServerConnection == null) if (args.WebSession.ServerConnection == null)
{ {
return; return;
} }
//if connection is closing exit // if connection is closing exit
if (!response.KeepAlive) if (!response.KeepAlive)
{ {
return; return;
...@@ -268,17 +268,17 @@ namespace Titanium.Web.Proxy ...@@ -268,17 +268,17 @@ namespace Titanium.Web.Proxy
} }
finally finally
{ {
connection?.Dispose(); serverConnection?.Dispose();
} }
} }
/// <summary> /// <summary>
/// Handle a specific session (request/response sequence) /// Handle a specific session (request/response sequence)
/// </summary> /// </summary>
/// <param name="connection">The tcp connection.</param> /// <param name="serverConnection">The tcp connection.</param>
/// <param name="args">The session event arguments.</param> /// <param name="args">The session event arguments.</param>
/// <returns></returns> /// <returns></returns>
private async Task HandleHttpSessionRequestInternal(TcpConnection connection, SessionEventArgs args) private async Task HandleHttpSessionRequestInternal(TcpServerConnection serverConnection, SessionEventArgs args)
{ {
try try
{ {
...@@ -288,16 +288,16 @@ namespace Titanium.Web.Proxy ...@@ -288,16 +288,16 @@ namespace Titanium.Web.Proxy
var body = request.CompressBodyAndUpdateContentLength(); var body = request.CompressBodyAndUpdateContentLength();
//if expect continue is enabled then send the headers first // if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue // and see if server would return 100 conitinue
if (request.ExpectContinue) if (request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(serverConnection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
cancellationToken); cancellationToken);
} }
//If 100 continue was the response inform that to the client // If 100 continue was the response inform that to the client
if (Enable100ContinueBehaviour) if (Enable100ContinueBehaviour)
{ {
var clientStreamWriter = args.ProxyClient.ClientStreamWriter; var clientStreamWriter = args.ProxyClient.ClientStreamWriter;
...@@ -316,15 +316,15 @@ namespace Titanium.Web.Proxy ...@@ -316,15 +316,15 @@ namespace Titanium.Web.Proxy
} }
} }
//If expect continue is not enabled then set the connectio and send request headers // If expect continue is not enabled then set the connectio and send request headers
if (!request.ExpectContinue) if (!request.ExpectContinue)
{ {
args.WebSession.SetConnection(connection); args.WebSession.SetConnection(serverConnection);
await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent, await args.WebSession.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
cancellationToken); cancellationToken);
} }
//check if content-length is > 0 // check if content-length is > 0
if (request.ContentLength > 0) if (request.ContentLength > 0)
{ {
if (request.IsBodyRead) if (request.IsBodyRead)
...@@ -345,7 +345,7 @@ namespace Titanium.Web.Proxy ...@@ -345,7 +345,7 @@ namespace Titanium.Web.Proxy
} }
} }
//If not expectation failed response was returned by server then parse response // If not expectation failed response was returned by server then parse response
if (!request.ExpectationFailed) if (!request.ExpectationFailed)
{ {
await HandleHttpSessionResponse(args); await HandleHttpSessionResponse(args);
...@@ -362,10 +362,31 @@ namespace Titanium.Web.Proxy ...@@ -362,10 +362,31 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="args">The session event arguments.</param> /// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocol"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private Task<TcpServerConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect,
SslApplicationProtocol applicationProtocol, CancellationToken cancellationToken)
{
List<SslApplicationProtocol> applicationProtocols = null;
if (applicationProtocol != default)
{
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
return GetServerConnection(args, isConnect, applicationProtocols, cancellationToken);
}
/// <summary>
/// Create a server connection.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocols"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param> /// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns> /// <returns></returns>
private async Task<TcpConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect, private async Task<TcpServerConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect,
CancellationToken cancellationToken) List<SslApplicationProtocol> applicationProtocols, CancellationToken cancellationToken)
{ {
ExternalProxy customUpStreamProxy = null; ExternalProxy customUpStreamProxy = null;
...@@ -380,8 +401,8 @@ namespace Titanium.Web.Proxy ...@@ -380,8 +401,8 @@ namespace Titanium.Web.Proxy
return await tcpConnectionFactory.CreateClient( return await tcpConnectionFactory.CreateClient(
args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port, args.WebSession.Request.RequestUri.Port,
args.WebSession.ConnectRequest?.ClientHelloInfo?.GetAlpn(), args.WebSession.Request.HttpVersion,
args.WebSession.Request.HttpVersion, isHttps, isConnect, isHttps, applicationProtocols, isConnect,
this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint, this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy), customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy),
cancellationToken); cancellationToken);
...@@ -390,12 +411,23 @@ namespace Titanium.Web.Proxy ...@@ -390,12 +411,23 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Prepare the request headers so that we can avoid encodings not parsable by this proxy /// Prepare the request headers so that we can avoid encodings not parsable by this proxy
/// </summary> /// </summary>
/// <param name="requestHeaders"></param>
private void PrepareRequestHeaders(HeaderCollection requestHeaders) private void PrepareRequestHeaders(HeaderCollection requestHeaders)
{ {
if (requestHeaders.HeaderExists(KnownHeaders.AcceptEncoding)) var acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding);
if (acceptEncoding != null)
{ {
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, "gzip,deflate"); var supportedAcceptEncoding = new List<string>();
//only allow proxy supported compressions
supportedAcceptEncoding.AddRange(acceptEncoding.Split(',')
.Select(x => x.Trim())
.Where(x => proxySupportedCompressions.Contains(x)));
//uncompressed is always supported by proxy
supportedAcceptEncoding.Add("identity");
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, string.Join(",", supportedAcceptEncoding));
} }
requestHeaders.FixProxyHeaders(); requestHeaders.FixProxyHeaders();
......
...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy ...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Handle the response from server. /// Handle the response from server.
/// </summary> /// </summary>
partial class ProxyServer public partial class ProxyServer
{ {
/// <summary> /// <summary>
/// Called asynchronously when a request was successfully and we received the response. /// Called asynchronously when a request was successfully and we received the response.
...@@ -23,13 +23,14 @@ namespace Titanium.Web.Proxy ...@@ -23,13 +23,14 @@ namespace Titanium.Web.Proxy
try try
{ {
var cancellationToken = args.CancellationTokenSource.Token; var cancellationToken = args.CancellationTokenSource.Token;
//read response & headers from server
// read response & headers from server
await args.WebSession.ReceiveResponse(cancellationToken); await args.WebSession.ReceiveResponse(cancellationToken);
var response = args.WebSession.Response; var response = args.WebSession.Response;
args.ReRequest = false; args.ReRequest = false;
//check for windows authentication // check for windows authentication
if (isWindowsAuthenticationEnabledAndSupported) if (isWindowsAuthenticationEnabledAndSupported)
{ {
if (response.StatusCode == (int)HttpStatusCode.Unauthorized) if (response.StatusCode == (int)HttpStatusCode.Unauthorized)
...@@ -38,13 +39,13 @@ namespace Titanium.Web.Proxy ...@@ -38,13 +39,13 @@ namespace Titanium.Web.Proxy
} }
else else
{ {
WinAuthEndPoint.AuthenticatedResponse(args.WebSession.RequestId); WinAuthEndPoint.AuthenticatedResponse(args.WebSession.Data);
} }
} }
response.OriginalHasBody = response.HasBody; response.OriginalHasBody = response.HasBody;
//if user requested call back then do it // if user requested call back then do it
if (!response.Locked) if (!response.Locked)
{ {
await InvokeBeforeResponse(args); await InvokeBeforeResponse(args);
...@@ -61,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -61,7 +62,7 @@ namespace Titanium.Web.Proxy
if (!response.TerminateResponse) if (!response.TerminateResponse)
{ {
//syphon out the response body from server before setting the new body // syphon out the response body from server before setting the new body
await args.SyphonOutBodyAsync(false, cancellationToken); await args.SyphonOutBodyAsync(false, cancellationToken);
} }
else else
...@@ -73,11 +74,11 @@ namespace Titanium.Web.Proxy ...@@ -73,11 +74,11 @@ namespace Titanium.Web.Proxy
return; return;
} }
//if user requested to send request again // if user requested to send request again
//likely after making modifications from User Response Handler // likely after making modifications from User Response Handler
if (args.ReRequest) if (args.ReRequest)
{ {
//clear current response // clear current response
await args.ClearResponse(cancellationToken); await args.ClearResponse(cancellationToken);
await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args); await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
return; return;
...@@ -85,7 +86,7 @@ namespace Titanium.Web.Proxy ...@@ -85,7 +86,7 @@ namespace Titanium.Web.Proxy
response.Locked = true; response.Locked = true;
//Write back to client 100-conitinue response if that's what server returned // Write back to client 100-conitinue response if that's what server returned
if (response.Is100Continue) if (response.Is100Continue)
{ {
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion,
...@@ -110,12 +111,12 @@ namespace Titanium.Web.Proxy ...@@ -110,12 +111,12 @@ namespace Titanium.Web.Proxy
} }
else else
{ {
//Write back response status to client // Write back response status to client
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode,
response.StatusDescription, cancellationToken); response.StatusDescription, cancellationToken);
await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken); await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken);
//Write body if exists // Write body if exists
if (response.HasBody) if (response.HasBody)
{ {
await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None, await args.CopyResponseBodyAsync(clientStreamWriter, TransformationMode.None,
......
<StyleCopSettings Version="105">
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<Rules>
<Rule Name="FileMustHaveHeader">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParameterDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementReturnValueDocumentationMustHaveText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PropertySummaryDocumentationMustMatchAccessors">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstructorSummaryDocumentationMustBeginWithStandardText">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="EnumerationItemsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="DocumentationTextMustContainWhitespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FileHeaderMustShowCopyright">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementParametersMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PartialElementsMustBeDocumented">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.ReadabilityRules">
<Rules>
<Rule Name="PrefixLocalCallsWithThis">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParameterMustFollowComma">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="SplitParametersMustStartOnLineAfterDeclaration">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ParametersMustBeOnSameLineOrSeparateLines">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="PrefixCallsCorrectly">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="ElementMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StaticReadonlyFieldsMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstFieldNamesMustBeginWithUpperCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustNotUseHungarianNotation">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="FieldNamesMustBeginWithLowerCaseLetter">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
<Analyzer AnalyzerId="StyleCop.CSharp.OrderingRules">
<Rules>
<Rule Name="UsingDirectivesMustBePlacedWithinNamespace">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustBeOrderedByAccess">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="StaticElementsMustAppearBeforeInstanceElements">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ElementsMustAppearInTheCorrectOrder">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
<Rule Name="ConstantsMustAppearBeforeFields">
<RuleSettings>
<BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
</Analyzers>
</StyleCopSettings>
\ No newline at end of file
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
<Reference Include="BouncyCastle.Crypto, Version=1.8.2.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL"> <Reference Include="BouncyCastle.Crypto, Version=1.8.2.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
<HintPath>..\packages\Portable.BouncyCastle.1.8.2\lib\net40\BouncyCastle.Crypto.dll</HintPath> <HintPath>..\packages\Portable.BouncyCastle.1.8.2\lib\net40\BouncyCastle.Crypto.dll</HintPath>
</Reference> </Reference>
<Reference Include="StreamExtended, Version=1.0.147.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.160.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\packages\StreamExtended.1.0.147-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\packages\StreamExtended.1.0.160-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="StreamExtended" Version="1.0.147-beta" /> <PackageReference Include="StreamExtended" Version="1.0.164" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright> <copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags> <tags></tags>
<dependencies> <dependencies>
<dependency id="StreamExtended" version="1.0.147-beta" /> <dependency id="StreamExtended" version="1.0.164" />
<dependency id="Portable.BouncyCastle" version="1.8.2" /> <dependency id="Portable.BouncyCastle" version="1.8.2" />
</dependencies> </dependencies>
</metadata> </metadata>
......
using System; using System;
using System.IO;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication; using System.Security.Authentication;
...@@ -8,29 +9,30 @@ using StreamExtended; ...@@ -8,29 +9,30 @@ using StreamExtended;
using StreamExtended.Helpers; using StreamExtended.Helpers;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer public partial class ProxyServer
{ {
/// <summary> /// <summary>
/// This is called when this proxy acts as a reverse proxy (like a real http server). /// This is called when this proxy acts as a reverse proxy (like a real http server).
/// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client
/// </summary> /// </summary>
/// <param name="endPoint">The transparent endpoint.</param> /// <param name="endPoint">The transparent endpoint.</param>
/// <param name="tcpClient">The client.</param> /// <param name="clientConnection">The client connection.</param>
/// <returns></returns> /// <returns></returns>
private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient) private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection)
{ {
var cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token; var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize); var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferSize);
var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
try try
...@@ -67,27 +69,24 @@ namespace Titanium.Web.Proxy ...@@ -67,27 +69,24 @@ namespace Titanium.Web.Proxy
string certName = HttpHelper.GetWildCardDomainName(httpsHostName); string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
var certificate = await CertificateManager.CreateCertificateAsync(certName); var certificate = await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate // Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
//HTTPS server created - we can now decrypt the client's traffic // HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamReader.Dispose();
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new Exception(
$"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e));
sslStream?.Dispose(); sslStream?.Dispose();
return; throw new ProxyConnectException(
$"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e, null);
} }
} }
else else
{ {
//create new connection // create new connection
var connection = new TcpClient(UpStreamEndPoint); var connection = new TcpClient(UpStreamEndPoint);
await connection.ConnectAsync(httpsHostName, endPoint.Port); await connection.ConnectAsync(httpsHostName, endPoint.Port);
connection.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; connection.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
...@@ -100,7 +99,7 @@ namespace Titanium.Web.Proxy ...@@ -100,7 +99,7 @@ namespace Titanium.Web.Proxy
int available = clientStream.Available; int available = clientStream.Available;
if (available > 0) if (available > 0)
{ {
//send the buffered data // send the buffered data
var data = BufferPool.GetBuffer(BufferSize); var data = BufferPool.GetBuffer(BufferSize);
try try
...@@ -116,7 +115,7 @@ namespace Titanium.Web.Proxy ...@@ -116,7 +115,7 @@ namespace Titanium.Web.Proxy
} }
} }
//var serverHelloInfo = await SslTools.PeekServerHello(serverStream); ////var serverHelloInfo = await SslTools.PeekServerHello(serverStream);
await TcpHelper.SendRaw(clientStream, serverStream, BufferSize, await TcpHelper.SendRaw(clientStream, serverStream, BufferSize,
null, null, cancellationTokenSource, ExceptionFunc); null, null, cancellationTokenSource, ExceptionFunc);
...@@ -124,14 +123,29 @@ namespace Titanium.Web.Proxy ...@@ -124,14 +123,29 @@ namespace Titanium.Web.Proxy
} }
} }
//HTTPS server created - we can now decrypt the client's traffic // HTTPS server created - we can now decrypt the client's traffic
//Now create the request // Now create the request
await HandleHttpSessionRequest(endPoint, tcpClient, clientStream, clientStreamReader, await HandleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
clientStreamWriter, cancellationTokenSource, isHttps ? httpsHostName : null, null, true); cancellationTokenSource, isHttps ? httpsHostName : null, null);
}
catch (ProxyException e)
{
OnException(clientStream, e);
}
catch (IOException e)
{
OnException(clientStream, new Exception("Connection was aborted", e));
}
catch (SocketException e)
{
OnException(clientStream, new Exception("Could not connect", e));
}
catch (Exception e)
{
OnException(clientStream, new Exception("Error occured in whilst handling the client", e));
} }
finally finally
{ {
clientStreamReader.Dispose();
clientStream.Dispose(); clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested) if (!cancellationTokenSource.IsCancellationRequested)
{ {
......
...@@ -19,7 +19,8 @@ namespace Titanium.Web.Proxy ...@@ -19,7 +19,8 @@ namespace Titanium.Web.Proxy
private static readonly HashSet<string> authHeaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) private static readonly HashSet<string> authHeaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{ {
"WWW-Authenticate", "WWW-Authenticate",
//IIS 6.0 messed up names below
// IIS 6.0 messed up names below
"WWWAuthenticate", "WWWAuthenticate",
"NTLMAuthorization", "NTLMAuthorization",
"NegotiateAuthorization", "NegotiateAuthorization",
...@@ -51,7 +52,7 @@ namespace Titanium.Web.Proxy ...@@ -51,7 +52,7 @@ namespace Titanium.Web.Proxy
var response = args.WebSession.Response; var response = args.WebSession.Response;
//check in non-unique headers first // check in non-unique headers first
var header = response.Headers.NonUniqueHeaders.FirstOrDefault(x => authHeaderNames.Contains(x.Key)); var header = response.Headers.NonUniqueHeaders.FirstOrDefault(x => authHeaderNames.Contains(x.Key));
if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>())) if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>()))
...@@ -66,12 +67,12 @@ namespace Titanium.Web.Proxy ...@@ -66,12 +67,12 @@ namespace Titanium.Web.Proxy
x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase))); x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase)));
} }
//check in unique headers // check in unique headers
if (authHeader == null) if (authHeader == null)
{ {
headerName = null; headerName = null;
//check in non-unique headers first // check in non-unique headers first
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key)); var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key));
if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>())) if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>()))
...@@ -95,7 +96,7 @@ namespace Titanium.Web.Proxy ...@@ -95,7 +96,7 @@ namespace Titanium.Web.Proxy
var expectedAuthState = var expectedAuthState =
scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED; scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED;
if (!WinAuthEndPoint.ValidateWinAuthState(args.WebSession.RequestId, expectedAuthState)) if (!WinAuthEndPoint.ValidateWinAuthState(args.WebSession.Data, expectedAuthState))
{ {
// Invalid state, create proper error message to client // Invalid state, create proper error message to client
await RewriteUnauthorizedResponse(args); await RewriteUnauthorizedResponse(args);
...@@ -104,50 +105,51 @@ namespace Titanium.Web.Proxy ...@@ -104,50 +105,51 @@ namespace Titanium.Web.Proxy
var request = args.WebSession.Request; var request = args.WebSession.Request;
//clear any existing headers to avoid confusing bad servers // clear any existing headers to avoid confusing bad servers
request.Headers.RemoveHeader(KnownHeaders.Authorization); request.Headers.RemoveHeader(KnownHeaders.Authorization);
//initial value will match exactly any of the schemes // initial value will match exactly any of the schemes
if (scheme != null) if (scheme != null)
{ {
string clientToken = WinAuthHandler.GetInitialAuthToken(request.Host, scheme, args.Id); string clientToken = WinAuthHandler.GetInitialAuthToken(request.Host, scheme, args.WebSession.Data);
string auth = string.Concat(scheme, clientToken); string auth = string.Concat(scheme, clientToken);
//replace existing authorization header if any // replace existing authorization header if any
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
//don't need to send body for Authorization request // don't need to send body for Authorization request
if (request.HasBody) if (request.HasBody)
{ {
request.ContentLength = 0; request.ContentLength = 0;
} }
} }
//challenge value will start with any of the scheme selected
else else
{ {
// challenge value will start with any of the scheme selected
scheme = authSchemes.First(x => scheme = authSchemes.First(x =>
authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) && authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) &&
authHeader.Value.Length > x.Length + 1); authHeader.Value.Length > x.Length + 1);
string serverToken = authHeader.Value.Substring(scheme.Length + 1); string serverToken = authHeader.Value.Substring(scheme.Length + 1);
string clientToken = WinAuthHandler.GetFinalAuthToken(request.Host, serverToken, args.Id); string clientToken = WinAuthHandler.GetFinalAuthToken(request.Host, serverToken, args.WebSession.Data);
string auth = string.Concat(scheme, clientToken); string auth = string.Concat(scheme, clientToken);
//there will be an existing header from initial client request // there will be an existing header from initial client request
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth); request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
//send body for final auth request // send body for final auth request
if (request.OriginalHasBody) if (request.OriginalHasBody)
{ {
request.ContentLength = request.Body.Length; request.ContentLength = request.Body.Length;
} }
} }
//Need to revisit this. // Need to revisit this.
//Should we cache all Set-Cokiee headers from server during auth process // Should we cache all Set-Cokiee headers from server during auth process
//and send it to client after auth? // and send it to client after auth?
// Let ResponseHandler send the updated request // Let ResponseHandler send the updated request
args.ReRequest = true; args.ReRequest = true;
...@@ -172,7 +174,7 @@ namespace Titanium.Web.Proxy ...@@ -172,7 +174,7 @@ namespace Titanium.Web.Proxy
// Add custom div to body to clarify that the proxy (not the client browser) failed authentication // Add custom div to body to clarify that the proxy (not the client browser) failed authentication
string authErrorMessage = string authErrorMessage =
"<div class=\"inserted-by-proxy\"><h2>NTLM authentication through Titanium.Web.Proxy (" + "<div class=\"inserted-by-proxy\"><h2>NTLM authentication through Titanium.Web.Proxy (" +
args.ProxyClient.TcpClient.Client.LocalEndPoint + args.ProxyClient.ClientConnection.LocalEndPoint +
") failed. Please check credentials.</h2></div>"; ") failed. Please check credentials.</h2></div>";
string originalErrorMessage = string originalErrorMessage =
"<div class=\"inserted-by-proxy\"><h3>Response from remote web server below.</h3></div><br/>"; "<div class=\"inserted-by-proxy\"><h3>Response from remote web server below.</h3></div><br/>";
......
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.2" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.2" targetFramework="net45" />
<package id="StreamExtended" version="1.0.147-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.164" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Delegate AsyncEventHandler&lt;TEventArgs&gt; <meta name="title" content="Delegate AsyncEventHandler&lt;TEventArgs&gt;
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class BeforeSslAuthenticateEventArgs <meta name="title" content="Class BeforeSslAuthenticateEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateSelectionEventArgs <meta name="title" content="Class CertificateSelectionEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateValidationEventArgs <meta name="title" content="Class CertificateValidationEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class MultipartRequestPartSentEventArgs <meta name="title" content="Class MultipartRequestPartSentEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgs <meta name="title" content="Class SessionEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -109,7 +109,7 @@ or when server terminates connection from proxy.</p> ...@@ -109,7 +109,7 @@ or when server terminates connection from proxy.</p>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc">SessionEventArgsBase.ExceptionFunc</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc">SessionEventArgsBase.ExceptionFunc</a>
</div> </div>
<div> <div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id">SessionEventArgsBase.Id</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData">SessionEventArgsBase.UserData</a>
</div> </div>
<div> <div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps">SessionEventArgsBase.IsHttps</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps">SessionEventArgsBase.IsHttps</a>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgsBase <meta name="title" content="Class SessionEventArgsBase
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -316,15 +316,14 @@ or when server terminates connection from proxy.</p> ...@@ -316,15 +316,14 @@ or when server terminates connection from proxy.</p>
</table> </table>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id*"></a> <a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id">Id</h4> <h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps">IsHttps</h4>
<div class="markdown level1 summary"><p>Returns a unique Id for this request/response session which is <div class="markdown level1 summary"><p>Does this session uses SSL?</p>
same as the RequestId of WebSession.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public Guid Id { get; }</code></pre> <pre><code class="lang-csharp hljs">public bool IsHttps { get; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -336,21 +335,21 @@ same as the RequestId of WebSession.</p> ...@@ -336,21 +335,21 @@ same as the RequestId of WebSession.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.guid">Guid</a></td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps*"></a> <a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsTransparent_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsTransparent*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps">IsHttps</h4> <h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsTransparent" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsTransparent">IsTransparent</h4>
<div class="markdown level1 summary"><p>Does this session uses SSL?</p> <div class="markdown level1 summary"><p>Is this a transparent endpoint?</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool IsHttps { get; }</code></pre> <pre><code class="lang-csharp hljs">public bool IsTransparent { get; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -369,14 +368,14 @@ same as the RequestId of WebSession.</p> ...@@ -369,14 +368,14 @@ same as the RequestId of WebSession.</p>
</table> </table>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsTransparent_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsTransparent*"></a> <a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_LocalEndPoint_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.LocalEndPoint*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsTransparent" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsTransparent">IsTransparent</h4> <h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_LocalEndPoint" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.LocalEndPoint">LocalEndPoint</h4>
<div class="markdown level1 summary"><p>Is this a transparent endpoint?</p> <div class="markdown level1 summary"><p>Local endpoint via which we make the request.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool IsTransparent { get; }</code></pre> <pre><code class="lang-csharp hljs">public ProxyEndPoint LocalEndPoint { get; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -388,21 +387,22 @@ same as the RequestId of WebSession.</p> ...@@ -388,21 +387,22 @@ same as the RequestId of WebSession.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td> <td><a class="xref" href="Titanium.Web.Proxy.Models.ProxyEndPoint.html">ProxyEndPoint</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_LocalEndPoint_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.LocalEndPoint*"></a> <a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_LocalEndPoint" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.LocalEndPoint">LocalEndPoint</h4> <h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData">UserData</h4>
<div class="markdown level1 summary"><p>Local endpoint via which we make the request.</p> <div class="markdown level1 summary"><p>Returns a user data for this request/response session which is
same as the user data of WebSession.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public ProxyEndPoint LocalEndPoint { get; }</code></pre> <pre><code class="lang-csharp hljs">public object UserData { get; set; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -414,7 +414,7 @@ same as the RequestId of WebSession.</p> ...@@ -414,7 +414,7 @@ same as the RequestId of WebSession.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="Titanium.Web.Proxy.Models.ProxyEndPoint.html">ProxyEndPoint</a></td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.object">Object</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
...@@ -492,7 +492,7 @@ within a proxy connection.</p> ...@@ -492,7 +492,7 @@ within a proxy connection.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.eventhandler-1">EventHandler</a>&lt;<a class="xref" href="Titanium.Web.Proxy.EventArguments.DataEventArgs.html">DataEventArgs</a>&gt;</td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.eventhandler-1">EventHandler</a>&lt;<span class="xref">StreamExtended.Network.DataEventArgs</span>&gt;</td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
...@@ -517,7 +517,7 @@ within a proxy connection.</p> ...@@ -517,7 +517,7 @@ within a proxy connection.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.eventhandler-1">EventHandler</a>&lt;<a class="xref" href="Titanium.Web.Proxy.EventArguments.DataEventArgs.html">DataEventArgs</a>&gt;</td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.eventhandler-1">EventHandler</a>&lt;<span class="xref">StreamExtended.Network.DataEventArgs</span>&gt;</td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class TunnelConnectSessionEventArgs <meta name="title" content="Class TunnelConnectSessionEventArgs
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc">SessionEventArgsBase.ExceptionFunc</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc">SessionEventArgsBase.ExceptionFunc</a>
</div> </div>
<div> <div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id">SessionEventArgsBase.Id</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData">SessionEventArgsBase.UserData</a>
</div> </div>
<div> <div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps">SessionEventArgsBase.IsHttps</a> <a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps">SessionEventArgsBase.IsHttps</a>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.EventArguments <meta name="title" content="Namespace Titanium.Web.Proxy.EventArguments
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -96,9 +96,6 @@ ...@@ -96,9 +96,6 @@
<h4><a class="xref" href="Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html">CertificateValidationEventArgs</a></h4> <h4><a class="xref" href="Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html">CertificateValidationEventArgs</a></h4>
<section><p>An argument passed on to the user for validating the server certificate <section><p>An argument passed on to the user for validating the server certificate
during SSL authentication.</p> during SSL authentication.</p>
</section>
<h4><a class="xref" href="Titanium.Web.Proxy.EventArguments.DataEventArgs.html">DataEventArgs</a></h4>
<section><p>Wraps the data sent/received by a proxy server instance.</p>
</section> </section>
<h4><a class="xref" href="Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html">MultipartRequestPartSentEventArgs</a></h4> <h4><a class="xref" href="Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html">MultipartRequestPartSentEventArgs</a></h4>
<section><p>Class that wraps the multipart sent request arguments.</p> <section><p>Class that wraps the multipart sent request arguments.</p>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Delegate ExceptionHandler <meta name="title" content="Delegate ExceptionHandler
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class BodyNotFoundException <meta name="title" content="Class BodyNotFoundException
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyAuthorizationException <meta name="title" content="Class ProxyAuthorizationException
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyException <meta name="title" content="Class ProxyException
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -169,7 +169,10 @@ ...@@ -169,7 +169,10 @@
<a id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor*"></a> <a id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_System_String_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor(System.String)">ProxyException(String)</h4> <h4 id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_System_String_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor(System.String)">ProxyException(String)</h4>
<div class="markdown level1 summary"><p>Instantiate a new instance of this exception - must be invoked by derived classes&apos; constructors</p> <div class="markdown level1 summary"><p>Initializes a new instance of the <a class="xref" href="Titanium.Web.Proxy.Exceptions.ProxyException.html">ProxyException</a> class.</p>
<ul>
<li>must be invoked by derived classes&apos; constructors</li>
</ul>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -198,7 +201,10 @@ ...@@ -198,7 +201,10 @@
<a id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor*"></a> <a id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_System_String_System_Exception_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor(System.String,System.Exception)">ProxyException(String, Exception)</h4> <h4 id="Titanium_Web_Proxy_Exceptions_ProxyException__ctor_System_String_System_Exception_" data-uid="Titanium.Web.Proxy.Exceptions.ProxyException.#ctor(System.String,System.Exception)">ProxyException(String, Exception)</h4>
<div class="markdown level1 summary"><p>Instantiate this exception - must be invoked by derived classes&apos; constructors</p> <div class="markdown level1 summary"><p>Initializes a new instance of the <a class="xref" href="Titanium.Web.Proxy.Exceptions.ProxyException.html">ProxyException</a> class.</p>
<ul>
<li>must be invoked by derived classes&apos; constructors</li>
</ul>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyHttpException <meta name="title" content="Class ProxyHttpException
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Exceptions <meta name="title" content="Namespace Titanium.Web.Proxy.Exceptions
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ConnectRequest <meta name="title" content="Class ConnectRequest
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ConnectResponse <meta name="title" content="Class ConnectResponse
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class HeaderCollection <meta name="title" content="Class HeaderCollection
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class HttpWebClient <meta name="title" content="Class HttpWebClient
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -230,14 +230,14 @@ If client is remote then this will return</p> ...@@ -230,14 +230,14 @@ If client is remote then this will return</p>
</table> </table>
<a id="Titanium_Web_Proxy_Http_HttpWebClient_RequestId_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.RequestId*"></a> <a id="Titanium_Web_Proxy_Http_HttpWebClient_Response_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.Response*"></a>
<h4 id="Titanium_Web_Proxy_Http_HttpWebClient_RequestId" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.RequestId">RequestId</h4> <h4 id="Titanium_Web_Proxy_Http_HttpWebClient_Response" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.Response">Response</h4>
<div class="markdown level1 summary"><p>Request ID.</p> <div class="markdown level1 summary"><p>Web Response.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public Guid RequestId { get; }</code></pre> <pre><code class="lang-csharp hljs">public Response Response { get; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -249,21 +249,21 @@ If client is remote then this will return</p> ...@@ -249,21 +249,21 @@ If client is remote then this will return</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.guid">Guid</a></td> <td><a class="xref" href="Titanium.Web.Proxy.Http.Response.html">Response</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<a id="Titanium_Web_Proxy_Http_HttpWebClient_Response_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.Response*"></a> <a id="Titanium_Web_Proxy_Http_HttpWebClient_UpStreamEndPoint_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint*"></a>
<h4 id="Titanium_Web_Proxy_Http_HttpWebClient_Response" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.Response">Response</h4> <h4 id="Titanium_Web_Proxy_Http_HttpWebClient_UpStreamEndPoint" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint">UpStreamEndPoint</h4>
<div class="markdown level1 summary"><p>Web Response.</p> <div class="markdown level1 summary"><p>Override UpStreamEndPoint for this request; Local NIC via request is made</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public Response Response { get; }</code></pre> <pre><code class="lang-csharp hljs">public IPEndPoint UpStreamEndPoint { get; set; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -275,21 +275,21 @@ If client is remote then this will return</p> ...@@ -275,21 +275,21 @@ If client is remote then this will return</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="Titanium.Web.Proxy.Http.Response.html">Response</a></td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.net.ipendpoint">IPEndPoint</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<a id="Titanium_Web_Proxy_Http_HttpWebClient_UpStreamEndPoint_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint*"></a> <a id="Titanium_Web_Proxy_Http_HttpWebClient_UserData_" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UserData*"></a>
<h4 id="Titanium_Web_Proxy_Http_HttpWebClient_UpStreamEndPoint" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint">UpStreamEndPoint</h4> <h4 id="Titanium_Web_Proxy_Http_HttpWebClient_UserData" data-uid="Titanium.Web.Proxy.Http.HttpWebClient.UserData">UserData</h4>
<div class="markdown level1 summary"><p>Override UpStreamEndPoint for this request; Local NIC via request is made</p> <div class="markdown level1 summary"><p>Gets or sets the user data.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public IPEndPoint UpStreamEndPoint { get; set; }</code></pre> <pre><code class="lang-csharp hljs">public object UserData { get; set; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
...@@ -301,7 +301,7 @@ If client is remote then this will return</p> ...@@ -301,7 +301,7 @@ If client is remote then this will return</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.net.ipendpoint">IPEndPoint</a></td> <td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.object">Object</a></td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class KnownHeaders <meta name="title" content="Class KnownHeaders
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class Request <meta name="title" content="Class Request
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class RequestResponseBase <meta name="title" content="Class RequestResponseBase
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -119,19 +119,21 @@ ...@@ -119,19 +119,21 @@
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">public abstract class RequestResponseBase</code></pre> <pre><code class="lang-csharp hljs">public abstract class RequestResponseBase</code></pre>
</div> </div>
<h3 id="fields">Fields <h3 id="properties">Properties
</h3> </h3>
<h4 id="Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal">BodyInternal</h4> <a id="Titanium_Web_Proxy_Http_RequestResponseBase_Body_" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.Body*"></a>
<div class="markdown level1 summary"><p>Cached body content as byte array.</p> <h4 id="Titanium_Web_Proxy_Http_RequestResponseBase_Body" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.Body">Body</h4>
<div class="markdown level1 summary"><p>Body as byte array</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">protected byte[] BodyInternal</code></pre> <pre><code class="lang-csharp hljs">[Browsable(false)]
public byte[] Body { get; }</code></pre>
</div> </div>
<h5 class="fieldValue">Field Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
<thead> <thead>
<tr> <tr>
...@@ -146,19 +148,16 @@ ...@@ -146,19 +148,16 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h3 id="properties">Properties
</h3>
<a id="Titanium_Web_Proxy_Http_RequestResponseBase_Body_" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.Body*"></a> <a id="Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal_" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal*"></a>
<h4 id="Titanium_Web_Proxy_Http_RequestResponseBase_Body" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.Body">Body</h4> <h4 id="Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal">BodyInternal</h4>
<div class="markdown level1 summary"><p>Body as byte array</p> <div class="markdown level1 summary"><p>Cached body content as byte array.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
<div class="codewrapper"> <div class="codewrapper">
<pre><code class="lang-csharp hljs">[Browsable(false)] <pre><code class="lang-csharp hljs">protected byte[] BodyInternal { get; }</code></pre>
public byte[] Body { get; }</code></pre>
</div> </div>
<h5 class="propertyValue">Property Value</h5> <h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed"> <table class="table table-bordered table-striped table-condensed">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class Response <meta name="title" content="Class Response
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class GenericResponse <meta name="title" content="Class GenericResponse
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class OkResponse <meta name="title" content="Class OkResponse
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class RedirectResponse <meta name="title" content="Class RedirectResponse
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -186,7 +186,7 @@ ...@@ -186,7 +186,7 @@
<a id="Titanium_Web_Proxy_Http_Responses_RedirectResponse__ctor_" data-uid="Titanium.Web.Proxy.Http.Responses.RedirectResponse.#ctor*"></a> <a id="Titanium_Web_Proxy_Http_Responses_RedirectResponse__ctor_" data-uid="Titanium.Web.Proxy.Http.Responses.RedirectResponse.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_Http_Responses_RedirectResponse__ctor" data-uid="Titanium.Web.Proxy.Http.Responses.RedirectResponse.#ctor">RedirectResponse()</h4> <h4 id="Titanium_Web_Proxy_Http_Responses_RedirectResponse__ctor" data-uid="Titanium.Web.Proxy.Http.Responses.RedirectResponse.#ctor">RedirectResponse()</h4>
<div class="markdown level1 summary"><p>Constructor.</p> <div class="markdown level1 summary"><p>Initializes a new instance of the <a class="xref" href="Titanium.Web.Proxy.Http.Responses.RedirectResponse.html">RedirectResponse</a> class.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Http.Responses <meta name="title" content="Namespace Titanium.Web.Proxy.Http.Responses
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Http <meta name="title" content="Namespace Titanium.Web.Proxy.Http
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ExplicitProxyEndPoint <meta name="title" content="Class ExplicitProxyEndPoint
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ExternalProxy <meta name="title" content="Class ExternalProxy
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class HttpHeader <meta name="title" content="Class HttpHeader
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyEndPoint <meta name="title" content="Class ProxyEndPoint
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class TransparentProxyEndPoint <meta name="title" content="Class TransparentProxyEndPoint
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Models <meta name="title" content="Namespace Titanium.Web.Proxy.Models
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Enum CertificateEngine <meta name="title" content="Enum CertificateEngine
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateManager <meta name="title" content="Class CertificateManager
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Network <meta name="title" content="Namespace Titanium.Web.Proxy.Network
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyServer <meta name="title" content="Class ProxyServer
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
<h1 id="Titanium_Web_Proxy_ProxyServer" data-uid="Titanium.Web.Proxy.ProxyServer" class="text-break">Class ProxyServer <h1 id="Titanium_Web_Proxy_ProxyServer" data-uid="Titanium.Web.Proxy.ProxyServer" class="text-break">Class ProxyServer
</h1> </h1>
<div class="markdown level0 summary"><p>This object is the backbone of proxy. One can create as many instances as needed. <div class="markdown level0 summary"><p>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.</p> However care should be taken to avoid using the same listening ports across multiple instances.</p>
</div> </div>
<div class="markdown level0 conceptual"></div> <div class="markdown level0 conceptual"></div>
...@@ -234,7 +234,7 @@ prompting for UAC if required?</p> ...@@ -234,7 +234,7 @@ prompting for UAC if required?</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_AuthenticateUserFunc" data-uid="Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc">AuthenticateUserFunc</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_AuthenticateUserFunc" data-uid="Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc">AuthenticateUserFunc</h4>
<div class="markdown level1 summary"><p>A callback to authenticate clients. <div class="markdown level1 summary"><p>A callback to authenticate clients.
Parameters are username and password as provided by client. Parameters are username and password as provided by client.
Return true for successful authentication.</p> Should return true for successful authentication.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -392,7 +392,8 @@ Note: If enabled can reduce performance. Defaults to false.</p> ...@@ -392,7 +392,8 @@ Note: If enabled can reduce performance. Defaults to false.</p>
<a id="Titanium_Web_Proxy_ProxyServer_Enable100ContinueBehaviour_" data-uid="Titanium.Web.Proxy.ProxyServer.Enable100ContinueBehaviour*"></a> <a id="Titanium_Web_Proxy_ProxyServer_Enable100ContinueBehaviour_" data-uid="Titanium.Web.Proxy.ProxyServer.Enable100ContinueBehaviour*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_Enable100ContinueBehaviour" data-uid="Titanium.Web.Proxy.ProxyServer.Enable100ContinueBehaviour">Enable100ContinueBehaviour</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_Enable100ContinueBehaviour" data-uid="Titanium.Web.Proxy.ProxyServer.Enable100ContinueBehaviour">Enable100ContinueBehaviour</h4>
<div class="markdown level1 summary"><p>Does this proxy uses the HTTP protocol 100 continue behaviour strictly? <div class="markdown level1 summary"><p>Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
Broken 100 contunue implementations on server/client may cause problems if enabled.</p> Broken 100 contunue implementations on server/client may cause problems if enabled.
Defaults to false.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -418,7 +419,7 @@ Broken 100 contunue implementations on server/client may cause problems if enabl ...@@ -418,7 +419,7 @@ Broken 100 contunue implementations on server/client may cause problems if enabl
<a id="Titanium_Web_Proxy_ProxyServer_EnableWinAuth_" data-uid="Titanium.Web.Proxy.ProxyServer.EnableWinAuth*"></a> <a id="Titanium_Web_Proxy_ProxyServer_EnableWinAuth_" data-uid="Titanium.Web.Proxy.ProxyServer.EnableWinAuth*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_EnableWinAuth" data-uid="Titanium.Web.Proxy.ProxyServer.EnableWinAuth">EnableWinAuth</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_EnableWinAuth" data-uid="Titanium.Web.Proxy.ProxyServer.EnableWinAuth">EnableWinAuth</h4>
<div class="markdown level1 summary"><p>Enable disable Windows Authentication (NTLM/Kerberos) <div class="markdown level1 summary"><p>Enable disable Windows Authentication (NTLM/Kerberos).
Note: NTLM/Kerberos will always send local credentials of current user Note: NTLM/Kerberos will always send local credentials of current user
running the proxy process. This is because a man running the proxy process. This is because a man
in middle attack with Windows domain authentication is not currently supported.</p> in middle attack with Windows domain authentication is not currently supported.</p>
...@@ -827,7 +828,7 @@ Defaults via any IP addresses of this machine.</p> ...@@ -827,7 +828,7 @@ Defaults via any IP addresses of this machine.</p>
<a id="Titanium_Web_Proxy_ProxyServer_Dispose_" data-uid="Titanium.Web.Proxy.ProxyServer.Dispose*"></a> <a id="Titanium_Web_Proxy_ProxyServer_Dispose_" data-uid="Titanium.Web.Proxy.ProxyServer.Dispose*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_Dispose" data-uid="Titanium.Web.Proxy.ProxyServer.Dispose">Dispose()</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_Dispose" data-uid="Titanium.Web.Proxy.ProxyServer.Dispose">Dispose()</h4>
<div class="markdown level1 summary"><p>Dispose Proxy.</p> <div class="markdown level1 summary"><p>Dispose the Proxy instance.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -839,7 +840,7 @@ Defaults via any IP addresses of this machine.</p> ...@@ -839,7 +840,7 @@ Defaults via any IP addresses of this machine.</p>
<a id="Titanium_Web_Proxy_ProxyServer_RemoveEndPoint_" data-uid="Titanium.Web.Proxy.ProxyServer.RemoveEndPoint*"></a> <a id="Titanium_Web_Proxy_ProxyServer_RemoveEndPoint_" data-uid="Titanium.Web.Proxy.ProxyServer.RemoveEndPoint*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_RemoveEndPoint_Titanium_Web_Proxy_Models_ProxyEndPoint_" data-uid="Titanium.Web.Proxy.ProxyServer.RemoveEndPoint(Titanium.Web.Proxy.Models.ProxyEndPoint)">RemoveEndPoint(ProxyEndPoint)</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_RemoveEndPoint_Titanium_Web_Proxy_Models_ProxyEndPoint_" data-uid="Titanium.Web.Proxy.ProxyServer.RemoveEndPoint(Titanium.Web.Proxy.Models.ProxyEndPoint)">RemoveEndPoint(ProxyEndPoint)</h4>
<div class="markdown level1 summary"><p>Remove a proxy end point. <div class="markdown level1 summary"><p>Remove a proxy end point.
Will throw error if the end point does&apos;nt exist</p> Will throw error if the end point does&apos;nt exist.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -888,7 +889,8 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -888,7 +889,8 @@ Will throw error if the end point does&apos;nt exist</p>
<tr> <tr>
<td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td> <td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td>
<td><span class="parametername">endPoint</span></td> <td><span class="parametername">endPoint</span></td>
<td></td> <td><p>The explicit endpoint.</p>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -916,7 +918,8 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -916,7 +918,8 @@ Will throw error if the end point does&apos;nt exist</p>
<tr> <tr>
<td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td> <td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td>
<td><span class="parametername">endPoint</span></td> <td><span class="parametername">endPoint</span></td>
<td></td> <td><p>The explicit endpoint.</p>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -944,12 +947,14 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -944,12 +947,14 @@ Will throw error if the end point does&apos;nt exist</p>
<tr> <tr>
<td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td> <td><a class="xref" href="Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html">ExplicitProxyEndPoint</a></td>
<td><span class="parametername">endPoint</span></td> <td><span class="parametername">endPoint</span></td>
<td></td> <td><p>The explicit endpoint.</p>
</td>
</tr> </tr>
<tr> <tr>
<td><span class="xref">ProxyProtocolType</span></td> <td><span class="xref">ProxyProtocolType</span></td>
<td><span class="parametername">protocolType</span></td> <td><span class="parametername">protocolType</span></td>
<td></td> <td><p>The proxy protocol type.</p>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -980,7 +985,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -980,7 +985,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_AfterResponse" data-uid="Titanium.Web.Proxy.ProxyServer.AfterResponse">AfterResponse</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_AfterResponse" data-uid="Titanium.Web.Proxy.ProxyServer.AfterResponse">AfterResponse</h4>
<div class="markdown level1 summary"><p>Intercept after response from server.</p> <div class="markdown level1 summary"><p>Intercept after response event from server.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1005,7 +1010,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1005,7 +1010,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_BeforeRequest" data-uid="Titanium.Web.Proxy.ProxyServer.BeforeRequest">BeforeRequest</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_BeforeRequest" data-uid="Titanium.Web.Proxy.ProxyServer.BeforeRequest">BeforeRequest</h4>
<div class="markdown level1 summary"><p>Intercept request to server.</p> <div class="markdown level1 summary"><p>Intercept request event to server.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1030,7 +1035,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1030,7 +1035,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_BeforeResponse" data-uid="Titanium.Web.Proxy.ProxyServer.BeforeResponse">BeforeResponse</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_BeforeResponse" data-uid="Titanium.Web.Proxy.ProxyServer.BeforeResponse">BeforeResponse</h4>
<div class="markdown level1 summary"><p>Intercept response from server.</p> <div class="markdown level1 summary"><p>Intercept response event from server.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1055,7 +1060,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1055,7 +1060,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_ClientCertificateSelectionCallback" data-uid="Titanium.Web.Proxy.ProxyServer.ClientCertificateSelectionCallback">ClientCertificateSelectionCallback</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_ClientCertificateSelectionCallback" data-uid="Titanium.Web.Proxy.ProxyServer.ClientCertificateSelectionCallback">ClientCertificateSelectionCallback</h4>
<div class="markdown level1 summary"><p>Callback to override client certificate selection during mutual SSL authentication.</p> <div class="markdown level1 summary"><p>Event to override client certificate selection during mutual SSL authentication.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1080,7 +1085,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1080,7 +1085,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_ClientConnectionCountChanged" data-uid="Titanium.Web.Proxy.ProxyServer.ClientConnectionCountChanged">ClientConnectionCountChanged</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_ClientConnectionCountChanged" data-uid="Titanium.Web.Proxy.ProxyServer.ClientConnectionCountChanged">ClientConnectionCountChanged</h4>
<div class="markdown level1 summary"><p>Occurs when client connection count changed.</p> <div class="markdown level1 summary"><p>Event occurs when client connection count changed.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1105,7 +1110,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1105,7 +1110,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_ServerCertificateValidationCallback" data-uid="Titanium.Web.Proxy.ProxyServer.ServerCertificateValidationCallback">ServerCertificateValidationCallback</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_ServerCertificateValidationCallback" data-uid="Titanium.Web.Proxy.ProxyServer.ServerCertificateValidationCallback">ServerCertificateValidationCallback</h4>
<div class="markdown level1 summary"><p>Verifies the remote SSL certificate used for authentication.</p> <div class="markdown level1 summary"><p>Event to override the default verification logic of remote SSL certificate received during authentication.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
...@@ -1130,7 +1135,7 @@ Will throw error if the end point does&apos;nt exist</p> ...@@ -1130,7 +1135,7 @@ Will throw error if the end point does&apos;nt exist</p>
<h4 id="Titanium_Web_Proxy_ProxyServer_ServerConnectionCountChanged" data-uid="Titanium.Web.Proxy.ProxyServer.ServerConnectionCountChanged">ServerConnectionCountChanged</h4> <h4 id="Titanium_Web_Proxy_ProxyServer_ServerConnectionCountChanged" data-uid="Titanium.Web.Proxy.ProxyServer.ServerConnectionCountChanged">ServerConnectionCountChanged</h4>
<div class="markdown level1 summary"><p>Occurs when server connection count changed.</p> <div class="markdown level1 summary"><p>Event occurs when server connection count changed.</p>
</div> </div>
<div class="markdown level1 conceptual"></div> <div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5> <h5 class="decalaration">Declaration</h5>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy <meta name="title" content="Namespace Titanium.Web.Proxy
| Titanium Web Proxy "> | Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.2.0"> <meta name="generator" content="docfx 2.35.4.0">
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css"> <link rel="stylesheet" href="../styles/docfx.vendor.css">
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
<h3 id="classes">Classes <h3 id="classes">Classes
</h3> </h3>
<h4><a class="xref" href="Titanium.Web.Proxy.ProxyServer.html">ProxyServer</a></h4> <h4><a class="xref" href="Titanium.Web.Proxy.ProxyServer.html">ProxyServer</a></h4>
<section><p>This object is the backbone of proxy. One can create as many instances as needed. <section><p>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.</p> However care should be taken to avoid using the same listening ports across multiple instances.</p>
</section> </section>
<h3 id="delegates">Delegates <h3 id="delegates">Delegates
......
...@@ -40,9 +40,6 @@ ...@@ -40,9 +40,6 @@
<li> <li>
<a href="Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html" name="" title="CertificateValidationEventArgs">CertificateValidationEventArgs</a> <a href="Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html" name="" title="CertificateValidationEventArgs">CertificateValidationEventArgs</a>
</li> </li>
<li>
<a href="Titanium.Web.Proxy.EventArguments.DataEventArgs.html" name="" title="DataEventArgs">DataEventArgs</a>
</li>
<li> <li>
<a href="Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html" name="" title="MultipartRequestPartSentEventArgs">MultipartRequestPartSentEventArgs</a> <a href="Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html" name="" title="MultipartRequestPartSentEventArgs">MultipartRequestPartSentEventArgs</a>
</li> </li>
......
...@@ -19,15 +19,10 @@ ...@@ -19,15 +19,10 @@
"title": "Class CertificateValidationEventArgs | Titanium Web Proxy", "title": "Class CertificateValidationEventArgs | Titanium Web Proxy",
"keywords": "Class CertificateValidationEventArgs An argument passed on to the user for validating the server certificate during SSL authentication. Inheritance Object EventArgs CertificateValidationEventArgs Inherited Members EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class CertificateValidationEventArgs : EventArgs Properties Certificate Server certificate. Declaration public X509Certificate Certificate { get; } Property Value Type Description X509Certificate Chain Certificate chain. Declaration public X509Chain Chain { get; } Property Value Type Description X509Chain IsValid Is the given server certificate valid? Declaration public bool IsValid { get; set; } Property Value Type Description Boolean SslPolicyErrors SSL policy errors. Declaration public SslPolicyErrors SslPolicyErrors { get; } Property Value Type Description SslPolicyErrors" "keywords": "Class CertificateValidationEventArgs An argument passed on to the user for validating the server certificate during SSL authentication. Inheritance Object EventArgs CertificateValidationEventArgs Inherited Members EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class CertificateValidationEventArgs : EventArgs Properties Certificate Server certificate. Declaration public X509Certificate Certificate { get; } Property Value Type Description X509Certificate Chain Certificate chain. Declaration public X509Chain Chain { get; } Property Value Type Description X509Chain IsValid Is the given server certificate valid? Declaration public bool IsValid { get; set; } Property Value Type Description Boolean SslPolicyErrors SSL policy errors. Declaration public SslPolicyErrors SslPolicyErrors { get; } Property Value Type Description SslPolicyErrors"
}, },
"api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html",
"title": "Class DataEventArgs | Titanium Web Proxy",
"keywords": "Class DataEventArgs Wraps the data sent/received by a proxy server instance. Inheritance Object EventArgs DataEventArgs Inherited Members EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class DataEventArgs : EventArgs Properties Buffer The buffer with data. Declaration public byte[] Buffer { get; } Property Value Type Description System.Byte [] Count Length from offset in buffer with valid data. Declaration public int Count { get; } Property Value Type Description Int32 Offset Offset in buffer from which valid data begins. Declaration public int Offset { get; } Property Value Type Description Int32"
},
"api/Titanium.Web.Proxy.EventArguments.html": { "api/Titanium.Web.Proxy.EventArguments.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.html", "href": "api/Titanium.Web.Proxy.EventArguments.html",
"title": "Namespace Titanium.Web.Proxy.EventArguments | Titanium Web Proxy", "title": "Namespace Titanium.Web.Proxy.EventArguments | Titanium Web Proxy",
"keywords": "Namespace Titanium.Web.Proxy.EventArguments Classes BeforeSslAuthenticateEventArgs This is used in transparent endpoint before authenticating client. CertificateSelectionEventArgs An argument passed on to user for client certificate selection during mutual SSL authentication. CertificateValidationEventArgs An argument passed on to the user for validating the server certificate during SSL authentication. DataEventArgs Wraps the data sent/received by a proxy server instance. MultipartRequestPartSentEventArgs Class that wraps the multipart sent request arguments. SessionEventArgs 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. SessionEventArgsBase 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. TunnelConnectSessionEventArgs A class that wraps the state when a tunnel connect event happen for Explicit endpoints. Delegates AsyncEventHandler<TEventArgs> A generic asynchronous event handler used by the proxy." "keywords": "Namespace Titanium.Web.Proxy.EventArguments Classes BeforeSslAuthenticateEventArgs This is used in transparent endpoint before authenticating client. CertificateSelectionEventArgs An argument passed on to user for client certificate selection during mutual SSL authentication. CertificateValidationEventArgs An argument passed on to the user for validating the server certificate during SSL authentication. MultipartRequestPartSentEventArgs Class that wraps the multipart sent request arguments. SessionEventArgs 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. SessionEventArgsBase 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. TunnelConnectSessionEventArgs A class that wraps the state when a tunnel connect event happen for Explicit endpoints. Delegates AsyncEventHandler<TEventArgs> A generic asynchronous event handler used by the proxy."
}, },
"api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html": { "api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html", "href": "api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html",
...@@ -37,17 +32,17 @@ ...@@ -37,17 +32,17 @@
"api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html": { "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html", "href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html",
"title": "Class SessionEventArgs | Titanium Web Proxy", "title": "Class SessionEventArgs | Titanium Web Proxy",
"keywords": "Class SessionEventArgs 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. Inheritance Object EventArgs SessionEventArgsBase SessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferSize SessionEventArgsBase.ExceptionFunc SessionEventArgsBase.Id SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.Exception SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class SessionEventArgs : SessionEventArgsBase, IDisposable Constructors SessionEventArgs(Int32, ProxyEndPoint, Request, CancellationTokenSource, ExceptionHandler) Declaration protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint, Request request, CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc) Parameters Type Name Description Int32 bufferSize ProxyEndPoint endPoint Request request CancellationTokenSource cancellationTokenSource ExceptionHandler exceptionFunc Properties ReRequest Should we send the request again ? Declaration public bool ReRequest { get; set; } Property Value Type Description Boolean Methods Dispose() Implement any cleanup here Declaration public override void Dispose() Overrides SessionEventArgsBase.Dispose() GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers) Parameters Type Name Description System.Byte [] result The bytes to sent. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description String html The html content. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. GetRequestBody(CancellationToken) Gets the request body as bytes. Declaration public Task<byte[]> GetRequestBody(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < System.Byte []> The body as bytes. GetRequestBodyAsString(CancellationToken) Gets the request body as string. Declaration public Task<string> GetRequestBodyAsString(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < String > The body as string. GetResponseBody(CancellationToken) Gets the response body as bytes. Declaration public Task<byte[]> GetResponseBody(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < System.Byte []> The resulting bytes. GetResponseBodyAsString(CancellationToken) Gets the response body as string. Declaration public Task<string> GetResponseBodyAsString(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < String > The string body. Ok(Byte[], Dictionary<String, HttpHeader>) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description System.Byte [] result The html content bytes. Dictionary < String , HttpHeader > headers The HTTP headers. Ok(String, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description String html HTML content to sent. Dictionary < String , HttpHeader > headers HTTP response headers. Redirect(String) Redirect to provided URL. Declaration public void Redirect(string url) Parameters Type Name Description String url The URL to redirect. Respond(Response) Respond with given response object to client. Declaration public void Respond(Response response) Parameters Type Name Description Response response The response object. SetRequestBody(Byte[]) Sets the request body. Declaration public void SetRequestBody(byte[] body) Parameters Type Name Description System.Byte [] body The request body bytes. SetRequestBodyString(String) Sets the body with the specified string. Declaration public void SetRequestBodyString(string body) Parameters Type Name Description String body The request body string to set. SetResponseBody(Byte[]) Set the response body bytes. Declaration public void SetResponseBody(byte[] body) Parameters Type Name Description System.Byte [] body The body bytes to set. SetResponseBodyString(String) Replace the response body with the specified string. Declaration public void SetResponseBodyString(string body) Parameters Type Name Description String body The body string to set. TerminateServerConnection() Terminate the connection to server. Declaration public void TerminateServerConnection() Events MultipartRequestPartSent Occurs when multipart request part sent. Declaration public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent Event Type Type Description EventHandler < MultipartRequestPartSentEventArgs > Implements System.IDisposable" "keywords": "Class SessionEventArgs 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. Inheritance Object EventArgs SessionEventArgsBase SessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferSize SessionEventArgsBase.ExceptionFunc SessionEventArgsBase.UserData SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.Exception SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class SessionEventArgs : SessionEventArgsBase, IDisposable Constructors SessionEventArgs(Int32, ProxyEndPoint, Request, CancellationTokenSource, ExceptionHandler) Declaration protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint, Request request, CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc) Parameters Type Name Description Int32 bufferSize ProxyEndPoint endPoint Request request CancellationTokenSource cancellationTokenSource ExceptionHandler exceptionFunc Properties ReRequest Should we send the request again ? Declaration public bool ReRequest { get; set; } Property Value Type Description Boolean Methods Dispose() Implement any cleanup here Declaration public override void Dispose() Overrides SessionEventArgsBase.Dispose() GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers) Parameters Type Name Description System.Byte [] result The bytes to sent. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description String html The html content. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. GetRequestBody(CancellationToken) Gets the request body as bytes. Declaration public Task<byte[]> GetRequestBody(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < System.Byte []> The body as bytes. GetRequestBodyAsString(CancellationToken) Gets the request body as string. Declaration public Task<string> GetRequestBodyAsString(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < String > The body as string. GetResponseBody(CancellationToken) Gets the response body as bytes. Declaration public Task<byte[]> GetResponseBody(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < System.Byte []> The resulting bytes. GetResponseBodyAsString(CancellationToken) Gets the response body as string. Declaration public Task<string> GetResponseBodyAsString(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task < String > The string body. Ok(Byte[], Dictionary<String, HttpHeader>) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description System.Byte [] result The html content bytes. Dictionary < String , HttpHeader > headers The HTTP headers. Ok(String, Dictionary<String, HttpHeader>) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, Dictionary<string, HttpHeader> headers = null) Parameters Type Name Description String html HTML content to sent. Dictionary < String , HttpHeader > headers HTTP response headers. Redirect(String) Redirect to provided URL. Declaration public void Redirect(string url) Parameters Type Name Description String url The URL to redirect. Respond(Response) Respond with given response object to client. Declaration public void Respond(Response response) Parameters Type Name Description Response response The response object. SetRequestBody(Byte[]) Sets the request body. Declaration public void SetRequestBody(byte[] body) Parameters Type Name Description System.Byte [] body The request body bytes. SetRequestBodyString(String) Sets the body with the specified string. Declaration public void SetRequestBodyString(string body) Parameters Type Name Description String body The request body string to set. SetResponseBody(Byte[]) Set the response body bytes. Declaration public void SetResponseBody(byte[] body) Parameters Type Name Description System.Byte [] body The body bytes to set. SetResponseBodyString(String) Replace the response body with the specified string. Declaration public void SetResponseBodyString(string body) Parameters Type Name Description String body The body string to set. TerminateServerConnection() Terminate the connection to server. Declaration public void TerminateServerConnection() Events MultipartRequestPartSent Occurs when multipart request part sent. Declaration public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent Event Type Type Description EventHandler < MultipartRequestPartSentEventArgs > Implements System.IDisposable"
}, },
"api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html": { "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html", "href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html",
"title": "Class SessionEventArgsBase | Titanium Web Proxy", "title": "Class SessionEventArgsBase | Titanium Web Proxy",
"keywords": "Class SessionEventArgsBase 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. Inheritance Object EventArgs SessionEventArgsBase SessionEventArgs TunnelConnectSessionEventArgs Implements IDisposable Inherited Members EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public abstract class SessionEventArgsBase : EventArgs, IDisposable Constructors SessionEventArgsBase(Int32, ProxyEndPoint, CancellationTokenSource, Request, ExceptionHandler) Declaration protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, CancellationTokenSource cancellationTokenSource, Request request, ExceptionHandler exceptionFunc) Parameters Type Name Description Int32 bufferSize ProxyEndPoint endPoint CancellationTokenSource cancellationTokenSource Request request ExceptionHandler exceptionFunc Fields BufferSize Size of Buffers used by this object Declaration protected readonly int BufferSize Field Value Type Description Int32 ExceptionFunc Declaration protected readonly ExceptionHandler ExceptionFunc Field Value Type Description ExceptionHandler Properties ClientEndPoint Client End Point. Declaration public IPEndPoint ClientEndPoint { get; } Property Value Type Description IPEndPoint CustomUpStreamProxyUsed Are we using a custom upstream HTTP(S) proxy? Declaration public ExternalProxy CustomUpStreamProxyUsed { get; } Property Value Type Description ExternalProxy Exception The last exception that happened. Declaration public Exception Exception { get; } Property Value Type Description Exception Id Returns a unique Id for this request/response session which is same as the RequestId of WebSession. Declaration public Guid Id { get; } Property Value Type Description Guid IsHttps Does this session uses SSL? Declaration public bool IsHttps { get; } Property Value Type Description Boolean IsTransparent Is this a transparent endpoint? Declaration public bool IsTransparent { get; } Property Value Type Description Boolean LocalEndPoint Local endpoint via which we make the request. Declaration public ProxyEndPoint LocalEndPoint { get; } Property Value Type Description ProxyEndPoint WebSession A web session corresponding to a single request/response sequence within a proxy connection. Declaration public HttpWebClient WebSession { get; } Property Value Type Description HttpWebClient Methods Dispose() Implements cleanup here. Declaration public virtual void Dispose() TerminateSession() Terminates the session abruptly by terminating client/server connections. Declaration public void TerminateSession() Events DataReceived Fired when data is received within this session from client/server. Declaration public event EventHandler<DataEventArgs> DataReceived Event Type Type Description EventHandler < DataEventArgs > DataSent Fired when data is sent within this session to server/client. Declaration public event EventHandler<DataEventArgs> DataSent Event Type Type Description EventHandler < DataEventArgs > Implements System.IDisposable" "keywords": "Class SessionEventArgsBase 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. Inheritance Object EventArgs SessionEventArgsBase SessionEventArgs TunnelConnectSessionEventArgs Implements IDisposable Inherited Members EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public abstract class SessionEventArgsBase : EventArgs, IDisposable Constructors SessionEventArgsBase(Int32, ProxyEndPoint, CancellationTokenSource, Request, ExceptionHandler) Declaration protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, CancellationTokenSource cancellationTokenSource, Request request, ExceptionHandler exceptionFunc) Parameters Type Name Description Int32 bufferSize ProxyEndPoint endPoint CancellationTokenSource cancellationTokenSource Request request ExceptionHandler exceptionFunc Fields BufferSize Size of Buffers used by this object Declaration protected readonly int BufferSize Field Value Type Description Int32 ExceptionFunc Declaration protected readonly ExceptionHandler ExceptionFunc Field Value Type Description ExceptionHandler Properties ClientEndPoint Client End Point. Declaration public IPEndPoint ClientEndPoint { get; } Property Value Type Description IPEndPoint CustomUpStreamProxyUsed Are we using a custom upstream HTTP(S) proxy? Declaration public ExternalProxy CustomUpStreamProxyUsed { get; } Property Value Type Description ExternalProxy Exception The last exception that happened. Declaration public Exception Exception { get; } Property Value Type Description Exception IsHttps Does this session uses SSL? Declaration public bool IsHttps { get; } Property Value Type Description Boolean IsTransparent Is this a transparent endpoint? Declaration public bool IsTransparent { get; } Property Value Type Description Boolean LocalEndPoint Local endpoint via which we make the request. Declaration public ProxyEndPoint LocalEndPoint { get; } Property Value Type Description ProxyEndPoint UserData Returns a user data for this request/response session which is same as the user data of WebSession. Declaration public object UserData { get; set; } Property Value Type Description Object WebSession A web session corresponding to a single request/response sequence within a proxy connection. Declaration public HttpWebClient WebSession { get; } Property Value Type Description HttpWebClient Methods Dispose() Implements cleanup here. Declaration public virtual void Dispose() TerminateSession() Terminates the session abruptly by terminating client/server connections. Declaration public void TerminateSession() Events DataReceived Fired when data is received within this session from client/server. Declaration public event EventHandler<DataEventArgs> DataReceived Event Type Type Description EventHandler < StreamExtended.Network.DataEventArgs > DataSent Fired when data is sent within this session to server/client. Declaration public event EventHandler<DataEventArgs> DataSent Event Type Type Description EventHandler < StreamExtended.Network.DataEventArgs > Implements System.IDisposable"
}, },
"api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html": { "api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html", "href": "api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html",
"title": "Class TunnelConnectSessionEventArgs | Titanium Web Proxy", "title": "Class TunnelConnectSessionEventArgs | Titanium Web Proxy",
"keywords": "Class TunnelConnectSessionEventArgs A class that wraps the state when a tunnel connect event happen for Explicit endpoints. Inheritance Object EventArgs SessionEventArgsBase TunnelConnectSessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferSize SessionEventArgsBase.ExceptionFunc SessionEventArgsBase.Id SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.Exception SessionEventArgsBase.Dispose() SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class TunnelConnectSessionEventArgs : SessionEventArgsBase, IDisposable Properties DecryptSsl Should we decrypt the Ssl or relay it to server? Default is true. Declaration public bool DecryptSsl { get; set; } Property Value Type Description Boolean DenyConnect When set to true it denies the connect request with a Forbidden status. Declaration public bool DenyConnect { get; set; } Property Value Type Description Boolean IsHttpsConnect Is this a connect request to secure HTTP server? Or is it to someother protocol. Declaration public bool IsHttpsConnect { get; } Property Value Type Description Boolean Implements System.IDisposable" "keywords": "Class TunnelConnectSessionEventArgs A class that wraps the state when a tunnel connect event happen for Explicit endpoints. Inheritance Object EventArgs SessionEventArgsBase TunnelConnectSessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferSize SessionEventArgsBase.ExceptionFunc SessionEventArgsBase.UserData SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.Exception SessionEventArgsBase.Dispose() SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() EventArgs.Empty Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.EventArguments Assembly : Titanium.Web.Proxy.dll Syntax public class TunnelConnectSessionEventArgs : SessionEventArgsBase, IDisposable Properties DecryptSsl Should we decrypt the Ssl or relay it to server? Default is true. Declaration public bool DecryptSsl { get; set; } Property Value Type Description Boolean DenyConnect When set to true it denies the connect request with a Forbidden status. Declaration public bool DenyConnect { get; set; } Property Value Type Description Boolean IsHttpsConnect Is this a connect request to secure HTTP server? Or is it to someother protocol. Declaration public bool IsHttpsConnect { get; } Property Value Type Description Boolean Implements System.IDisposable"
}, },
"api/Titanium.Web.Proxy.ExceptionHandler.html": { "api/Titanium.Web.Proxy.ExceptionHandler.html": {
"href": "api/Titanium.Web.Proxy.ExceptionHandler.html", "href": "api/Titanium.Web.Proxy.ExceptionHandler.html",
...@@ -72,7 +67,7 @@ ...@@ -72,7 +67,7 @@
"api/Titanium.Web.Proxy.Exceptions.ProxyException.html": { "api/Titanium.Web.Proxy.Exceptions.ProxyException.html": {
"href": "api/Titanium.Web.Proxy.Exceptions.ProxyException.html", "href": "api/Titanium.Web.Proxy.Exceptions.ProxyException.html",
"title": "Class ProxyException | Titanium Web Proxy", "title": "Class ProxyException | Titanium Web Proxy",
"keywords": "Class ProxyException Base class exception associated with this proxy server. Inheritance Object Exception ProxyException BodyNotFoundException ProxyAuthorizationException 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 abstract class ProxyException : Exception, ISerializable, _Exception Constructors ProxyException(String) Instantiate a new instance of this exception - must be invoked by derived classes' constructors Declaration protected ProxyException(string message) Parameters Type Name Description String message Exception message ProxyException(String, Exception) Instantiate this exception - must be invoked by derived classes' constructors Declaration protected ProxyException(string message, Exception innerException) Parameters Type Name Description String message Excception message Exception innerException Inner exception associated Implements System.Runtime.Serialization.ISerializable System.Runtime.InteropServices._Exception" "keywords": "Class ProxyException Base class exception associated with this proxy server. Inheritance Object Exception ProxyException BodyNotFoundException ProxyAuthorizationException 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 abstract class ProxyException : Exception, ISerializable, _Exception Constructors ProxyException(String) Initializes a new instance of the ProxyException class. must be invoked by derived classes' constructors Declaration protected ProxyException(string message) Parameters Type Name Description String message Exception message ProxyException(String, Exception) Initializes a new instance of the ProxyException class. must be invoked by derived classes' constructors Declaration protected ProxyException(string message, Exception innerException) Parameters Type Name Description String message Excception message Exception innerException Inner exception associated Implements System.Runtime.Serialization.ISerializable System.Runtime.InteropServices._Exception"
}, },
"api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html": { "api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html": {
"href": "api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html", "href": "api/Titanium.Web.Proxy.Exceptions.ProxyHttpException.html",
...@@ -82,7 +77,7 @@ ...@@ -82,7 +77,7 @@
"api/Titanium.Web.Proxy.html": { "api/Titanium.Web.Proxy.html": {
"href": "api/Titanium.Web.Proxy.html", "href": "api/Titanium.Web.Proxy.html",
"title": "Namespace Titanium.Web.Proxy | Titanium Web Proxy", "title": "Namespace Titanium.Web.Proxy | Titanium Web Proxy",
"keywords": "Namespace Titanium.Web.Proxy Classes ProxyServer This object 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. Delegates ExceptionHandler A delegate to catch exceptions occuring in proxy." "keywords": "Namespace Titanium.Web.Proxy Classes 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. Delegates ExceptionHandler A delegate to catch exceptions occuring in proxy."
}, },
"api/Titanium.Web.Proxy.Http.ConnectRequest.html": { "api/Titanium.Web.Proxy.Http.ConnectRequest.html": {
"href": "api/Titanium.Web.Proxy.Http.ConnectRequest.html", "href": "api/Titanium.Web.Proxy.Http.ConnectRequest.html",
...@@ -107,7 +102,7 @@ ...@@ -107,7 +102,7 @@
"api/Titanium.Web.Proxy.Http.HttpWebClient.html": { "api/Titanium.Web.Proxy.Http.HttpWebClient.html": {
"href": "api/Titanium.Web.Proxy.Http.HttpWebClient.html", "href": "api/Titanium.Web.Proxy.Http.HttpWebClient.html",
"title": "Class HttpWebClient | Titanium Web Proxy", "title": "Class HttpWebClient | Titanium Web Proxy",
"keywords": "Class HttpWebClient Used to communicate with the server over HTTP(S) Inheritance Object HttpWebClient 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.Http Assembly : Titanium.Web.Proxy.dll Syntax public class HttpWebClient Properties ConnectRequest Headers passed with Connect. Declaration public ConnectRequest ConnectRequest { get; } Property Value Type Description ConnectRequest IsHttps Is Https? Declaration public bool IsHttps { get; } Property Value Type Description Boolean ProcessId 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 Declaration public Lazy<int> ProcessId { get; } Property Value Type Description Lazy < Int32 > Request Web Request. Declaration public Request Request { get; } Property Value Type Description Request RequestId Request ID. Declaration public Guid RequestId { get; } Property Value Type Description Guid Response Web Response. Declaration public Response Response { get; } Property Value Type Description Response UpStreamEndPoint Override UpStreamEndPoint for this request; Local NIC via request is made Declaration public IPEndPoint UpStreamEndPoint { get; set; } Property Value Type Description IPEndPoint" "keywords": "Class HttpWebClient Used to communicate with the server over HTTP(S) Inheritance Object HttpWebClient 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.Http Assembly : Titanium.Web.Proxy.dll Syntax public class HttpWebClient Properties ConnectRequest Headers passed with Connect. Declaration public ConnectRequest ConnectRequest { get; } Property Value Type Description ConnectRequest IsHttps Is Https? Declaration public bool IsHttps { get; } Property Value Type Description Boolean ProcessId 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 Declaration public Lazy<int> ProcessId { get; } Property Value Type Description Lazy < Int32 > Request Web Request. Declaration public Request Request { get; } Property Value Type Description Request Response Web Response. Declaration public Response Response { get; } Property Value Type Description Response UpStreamEndPoint Override UpStreamEndPoint for this request; Local NIC via request is made Declaration public IPEndPoint UpStreamEndPoint { get; set; } Property Value Type Description IPEndPoint UserData Gets or sets the user data. Declaration public object UserData { get; set; } Property Value Type Description Object"
}, },
"api/Titanium.Web.Proxy.Http.KnownHeaders.html": { "api/Titanium.Web.Proxy.Http.KnownHeaders.html": {
"href": "api/Titanium.Web.Proxy.Http.KnownHeaders.html", "href": "api/Titanium.Web.Proxy.Http.KnownHeaders.html",
...@@ -122,7 +117,7 @@ ...@@ -122,7 +117,7 @@
"api/Titanium.Web.Proxy.Http.RequestResponseBase.html": { "api/Titanium.Web.Proxy.Http.RequestResponseBase.html": {
"href": "api/Titanium.Web.Proxy.Http.RequestResponseBase.html", "href": "api/Titanium.Web.Proxy.Http.RequestResponseBase.html",
"title": "Class RequestResponseBase | Titanium Web Proxy", "title": "Class RequestResponseBase | Titanium Web Proxy",
"keywords": "Class RequestResponseBase Inheritance Object RequestResponseBase Request Response Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Http Assembly : Titanium.Web.Proxy.dll Syntax public abstract class RequestResponseBase Fields BodyInternal Cached body content as byte array. Declaration protected byte[] BodyInternal Field Value Type Description System.Byte [] Properties Body Body as byte array Declaration [Browsable(false)] public byte[] Body { get; } Property Value Type Description System.Byte [] BodyString Body as string. Use the encoding specified to decode the byte[] data to string Declaration [Browsable(false)] public string BodyString { get; } Property Value Type Description String ContentEncoding Content encoding for this request/response. Declaration public string ContentEncoding { get; } Property Value Type Description String ContentLength Length of the body. Declaration public long ContentLength { get; set; } Property Value Type Description Int64 ContentType Content-type of the request/response. Declaration public string ContentType { get; set; } Property Value Type Description String Encoding Encoding for this request/response. Declaration public Encoding Encoding { get; } Property Value Type Description Encoding HasBody Has the request/response body? Declaration public abstract bool HasBody { get; } Property Value Type Description Boolean Headers Collection of all headers. Declaration public HeaderCollection Headers { get; } Property Value Type Description HeaderCollection HeaderText The header text. Declaration public abstract string HeaderText { get; } Property Value Type Description String HttpVersion Http Version. Declaration public Version HttpVersion { get; set; } Property Value Type Description Version IsBodyRead Was the body read by user? Declaration public bool IsBodyRead { get; } Property Value Type Description Boolean IsChunked Is body send as chunked bytes. Declaration public bool IsChunked { get; set; } Property Value Type Description Boolean KeepBody Keeps the body data after the session is finished. Declaration public bool KeepBody { get; set; } Property Value Type Description Boolean Methods ToString() Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()" "keywords": "Class RequestResponseBase Inheritance Object RequestResponseBase Request Response Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Http Assembly : Titanium.Web.Proxy.dll Syntax public abstract class RequestResponseBase Properties Body Body as byte array Declaration [Browsable(false)] public byte[] Body { get; } Property Value Type Description System.Byte [] BodyInternal Cached body content as byte array. Declaration protected byte[] BodyInternal { get; } Property Value Type Description System.Byte [] BodyString Body as string. Use the encoding specified to decode the byte[] data to string Declaration [Browsable(false)] public string BodyString { get; } Property Value Type Description String ContentEncoding Content encoding for this request/response. Declaration public string ContentEncoding { get; } Property Value Type Description String ContentLength Length of the body. Declaration public long ContentLength { get; set; } Property Value Type Description Int64 ContentType Content-type of the request/response. Declaration public string ContentType { get; set; } Property Value Type Description String Encoding Encoding for this request/response. Declaration public Encoding Encoding { get; } Property Value Type Description Encoding HasBody Has the request/response body? Declaration public abstract bool HasBody { get; } Property Value Type Description Boolean Headers Collection of all headers. Declaration public HeaderCollection Headers { get; } Property Value Type Description HeaderCollection HeaderText The header text. Declaration public abstract string HeaderText { get; } Property Value Type Description String HttpVersion Http Version. Declaration public Version HttpVersion { get; set; } Property Value Type Description Version IsBodyRead Was the body read by user? Declaration public bool IsBodyRead { get; } Property Value Type Description Boolean IsChunked Is body send as chunked bytes. Declaration public bool IsChunked { get; set; } Property Value Type Description Boolean KeepBody Keeps the body data after the session is finished. Declaration public bool KeepBody { get; set; } Property Value Type Description Boolean Methods ToString() Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()"
}, },
"api/Titanium.Web.Proxy.Http.Response.html": { "api/Titanium.Web.Proxy.Http.Response.html": {
"href": "api/Titanium.Web.Proxy.Http.Response.html", "href": "api/Titanium.Web.Proxy.Http.Response.html",
...@@ -147,7 +142,7 @@ ...@@ -147,7 +142,7 @@
"api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html": { "api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html": {
"href": "api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html", "href": "api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html",
"title": "Class RedirectResponse | Titanium Web Proxy", "title": "Class RedirectResponse | Titanium Web Proxy",
"keywords": "Class RedirectResponse Redirect response Inheritance Object RequestResponseBase Response RedirectResponse Inherited Members Response.StatusCode Response.StatusDescription Response.HasBody Response.KeepAlive Response.Is100Continue Response.ExpectationFailed Response.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.KeepBody RequestResponseBase.HttpVersion RequestResponseBase.Headers RequestResponseBase.ContentLength RequestResponseBase.ContentEncoding RequestResponseBase.Encoding RequestResponseBase.ContentType RequestResponseBase.IsChunked RequestResponseBase.Body RequestResponseBase.BodyString RequestResponseBase.IsBodyRead RequestResponseBase.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Http.Responses Assembly : Titanium.Web.Proxy.dll Syntax public sealed class RedirectResponse : Response Constructors RedirectResponse() Constructor. Declaration public RedirectResponse()" "keywords": "Class RedirectResponse Redirect response Inheritance Object RequestResponseBase Response RedirectResponse Inherited Members Response.StatusCode Response.StatusDescription Response.HasBody Response.KeepAlive Response.Is100Continue Response.ExpectationFailed Response.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.KeepBody RequestResponseBase.HttpVersion RequestResponseBase.Headers RequestResponseBase.ContentLength RequestResponseBase.ContentEncoding RequestResponseBase.Encoding RequestResponseBase.ContentType RequestResponseBase.IsChunked RequestResponseBase.Body RequestResponseBase.BodyString RequestResponseBase.IsBodyRead RequestResponseBase.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Http.Responses Assembly : Titanium.Web.Proxy.dll Syntax public sealed class RedirectResponse : Response Constructors RedirectResponse() Initializes a new instance of the RedirectResponse class. Declaration public RedirectResponse()"
}, },
"api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html": { "api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html": {
"href": "api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html", "href": "api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html",
...@@ -197,6 +192,6 @@ ...@@ -197,6 +192,6 @@
"api/Titanium.Web.Proxy.ProxyServer.html": { "api/Titanium.Web.Proxy.ProxyServer.html": {
"href": "api/Titanium.Web.Proxy.ProxyServer.html", "href": "api/Titanium.Web.Proxy.ProxyServer.html",
"title": "Class ProxyServer | Titanium Web Proxy", "title": "Class ProxyServer | Titanium Web Proxy",
"keywords": "Class ProxyServer This object 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 AuthenticateUserFunc A callback to authenticate clients. Parameters are username and password as provided by client. Return true for successful authentication. Declaration public Func<string, string, Task<bool>> AuthenticateUserFunc { get; set; } Property Value Type Description Func < String , String , Task < Boolean >> BufferSize Buffer size used throughout this proxy. 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. 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. Declaration public bool Enable100ContinueBehaviour { 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. 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. 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<SessionEventArgsBase, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , Task < ExternalProxy >> ProxyEndPoints A list of IpAddress and port this proxy is listening to. Declaration public List<ProxyEndPoint> ProxyEndPoints { get; set; } Property Value Type Description List < ProxyEndPoint > ProxyRealm Realm used during Proxy Basic Authentication. Declaration public string ProxyRealm { get; set; } Property Value Type Description String ProxyRunning Is the proxy currently running? Declaration public bool ProxyRunning { get; } 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 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 Proxy. 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 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 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 ProxyProtocolType protocolType 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 from server. Declaration public event AsyncEventHandler<SessionEventArgs> AfterResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeRequest Intercept request to server. Declaration public event AsyncEventHandler<SessionEventArgs> BeforeRequest Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeResponse Intercept response from server. Declaration public event AsyncEventHandler<SessionEventArgs> BeforeResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > ClientCertificateSelectionCallback Callback to override client certificate selection during mutual SSL authentication. Declaration public event AsyncEventHandler<CertificateSelectionEventArgs> ClientCertificateSelectionCallback Event Type Type Description AsyncEventHandler < CertificateSelectionEventArgs > ClientConnectionCountChanged Occurs when client connection count changed. Declaration public event EventHandler ClientConnectionCountChanged Event Type Type Description EventHandler ServerCertificateValidationCallback Verifies the remote SSL certificate used for authentication. Declaration public event AsyncEventHandler<CertificateValidationEventArgs> ServerCertificateValidationCallback Event Type Type Description AsyncEventHandler < CertificateValidationEventArgs > ServerConnectionCountChanged 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 AuthenticateUserFunc A callback to authenticate clients. Parameters are username and password as provided by client. Should return true for successful authentication. Declaration public Func<string, string, Task<bool>> AuthenticateUserFunc { get; set; } Property Value Type Description Func < String , String , Task < Boolean >> BufferSize Buffer size used throughout this proxy. 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. 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 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. 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. 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<SessionEventArgsBase, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , Task < ExternalProxy >> ProxyEndPoints A list of IpAddress and port this proxy is listening to. Declaration public List<ProxyEndPoint> ProxyEndPoints { get; set; } Property Value Type Description List < ProxyEndPoint > ProxyRealm Realm used during Proxy Basic Authentication. Declaration public string ProxyRealm { get; set; } Property Value Type Description String ProxyRunning Is the proxy currently running? Declaration public bool ProxyRunning { get; } 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 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<SessionEventArgs> AfterResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeRequest Intercept request event to server. Declaration public event AsyncEventHandler<SessionEventArgs> BeforeRequest Event Type Type Description AsyncEventHandler < SessionEventArgs > BeforeResponse Intercept response event from server. Declaration public event AsyncEventHandler<SessionEventArgs> BeforeResponse Event Type Type Description AsyncEventHandler < SessionEventArgs > ClientCertificateSelectionCallback Event to override client certificate selection during mutual SSL authentication. Declaration public event AsyncEventHandler<CertificateSelectionEventArgs> 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 ServerCertificateValidationCallback Event to override the default verification logic of remote SSL certificate received during authentication. Declaration public event AsyncEventHandler<CertificateValidationEventArgs> 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"
} }
} }
...@@ -855,7 +855,8 @@ $(function () { ...@@ -855,7 +855,8 @@ $(function () {
state.selectedTabs.splice(index, 1); state.selectedTabs.splice(index, 1);
} }
} }
firstVisibleTab.selected = true; var tab = firstVisibleTab;
tab.selected = true;
state.selectedTabs.push(tab.tabIds[0]); state.selectedTabs.push(tab.tabIds[0]);
} }
} }
......
...@@ -209,51 +209,6 @@ references: ...@@ -209,51 +209,6 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.SslPolicyErrors fullName: Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.SslPolicyErrors
nameWithType: CertificateValidationEventArgs.SslPolicyErrors nameWithType: CertificateValidationEventArgs.SslPolicyErrors
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs
name: DataEventArgs
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html
commentId: T:Titanium.Web.Proxy.EventArguments.DataEventArgs
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs
nameWithType: DataEventArgs
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer
name: Buffer
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Buffer
commentId: P:Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer
nameWithType: DataEventArgs.Buffer
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer*
name: Buffer
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Buffer_
commentId: Overload:Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Buffer
nameWithType: DataEventArgs.Buffer
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Count
name: Count
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Count
commentId: P:Titanium.Web.Proxy.EventArguments.DataEventArgs.Count
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Count
nameWithType: DataEventArgs.Count
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Count*
name: Count
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Count_
commentId: Overload:Titanium.Web.Proxy.EventArguments.DataEventArgs.Count
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Count
nameWithType: DataEventArgs.Count
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset
name: Offset
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Offset
commentId: P:Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset
nameWithType: DataEventArgs.Offset
- uid: Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset*
name: Offset
href: api/Titanium.Web.Proxy.EventArguments.DataEventArgs.html#Titanium_Web_Proxy_EventArguments_DataEventArgs_Offset_
commentId: Overload:Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.DataEventArgs.Offset
nameWithType: DataEventArgs.Offset
- uid: Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs - uid: Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs
name: MultipartRequestPartSentEventArgs name: MultipartRequestPartSentEventArgs
href: api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html href: api/Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html
...@@ -631,19 +586,6 @@ references: ...@@ -631,19 +586,6 @@ references:
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc
nameWithType: SessionEventArgsBase.ExceptionFunc nameWithType: SessionEventArgsBase.ExceptionFunc
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id
name: Id
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id
commentId: P:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id
nameWithType: SessionEventArgsBase.Id
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id*
name: Id
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_Id_
commentId: Overload:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Id
nameWithType: SessionEventArgsBase.Id
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps - uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps
name: IsHttps name: IsHttps
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps
...@@ -696,6 +638,19 @@ references: ...@@ -696,6 +638,19 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.TerminateSession fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.TerminateSession
nameWithType: SessionEventArgsBase.TerminateSession nameWithType: SessionEventArgsBase.TerminateSession
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData
name: UserData
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData
commentId: P:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData
nameWithType: SessionEventArgsBase.UserData
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData*
name: UserData
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData_
commentId: Overload:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.UserData
nameWithType: SessionEventArgsBase.UserData
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.WebSession - uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.WebSession
name: WebSession name: WebSession
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_WebSession href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_WebSession
...@@ -1175,19 +1130,6 @@ references: ...@@ -1175,19 +1130,6 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.Http.HttpWebClient.Request fullName: Titanium.Web.Proxy.Http.HttpWebClient.Request
nameWithType: HttpWebClient.Request nameWithType: HttpWebClient.Request
- uid: Titanium.Web.Proxy.Http.HttpWebClient.RequestId
name: RequestId
href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_RequestId
commentId: P:Titanium.Web.Proxy.Http.HttpWebClient.RequestId
fullName: Titanium.Web.Proxy.Http.HttpWebClient.RequestId
nameWithType: HttpWebClient.RequestId
- uid: Titanium.Web.Proxy.Http.HttpWebClient.RequestId*
name: RequestId
href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_RequestId_
commentId: Overload:Titanium.Web.Proxy.Http.HttpWebClient.RequestId
isSpec: "True"
fullName: Titanium.Web.Proxy.Http.HttpWebClient.RequestId
nameWithType: HttpWebClient.RequestId
- uid: Titanium.Web.Proxy.Http.HttpWebClient.Response - uid: Titanium.Web.Proxy.Http.HttpWebClient.Response
name: Response name: Response
href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_Response href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_Response
...@@ -1214,6 +1156,19 @@ references: ...@@ -1214,6 +1156,19 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint fullName: Titanium.Web.Proxy.Http.HttpWebClient.UpStreamEndPoint
nameWithType: HttpWebClient.UpStreamEndPoint nameWithType: HttpWebClient.UpStreamEndPoint
- uid: Titanium.Web.Proxy.Http.HttpWebClient.UserData
name: UserData
href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_UserData
commentId: P:Titanium.Web.Proxy.Http.HttpWebClient.UserData
fullName: Titanium.Web.Proxy.Http.HttpWebClient.UserData
nameWithType: HttpWebClient.UserData
- uid: Titanium.Web.Proxy.Http.HttpWebClient.UserData*
name: UserData
href: api/Titanium.Web.Proxy.Http.HttpWebClient.html#Titanium_Web_Proxy_Http_HttpWebClient_UserData_
commentId: Overload:Titanium.Web.Proxy.Http.HttpWebClient.UserData
isSpec: "True"
fullName: Titanium.Web.Proxy.Http.HttpWebClient.UserData
nameWithType: HttpWebClient.UserData
- uid: Titanium.Web.Proxy.Http.KnownHeaders - uid: Titanium.Web.Proxy.Http.KnownHeaders
name: KnownHeaders name: KnownHeaders
href: api/Titanium.Web.Proxy.Http.KnownHeaders.html href: api/Titanium.Web.Proxy.Http.KnownHeaders.html
...@@ -1567,7 +1522,14 @@ references: ...@@ -1567,7 +1522,14 @@ references:
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal - uid: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal
name: BodyInternal name: BodyInternal
href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal
commentId: F:Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal commentId: P:Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal
fullName: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal
nameWithType: RequestResponseBase.BodyInternal
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal*
name: BodyInternal
href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal_
commentId: Overload:Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal
isSpec: "True"
fullName: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal fullName: Titanium.Web.Proxy.Http.RequestResponseBase.BodyInternal
nameWithType: RequestResponseBase.BodyInternal nameWithType: RequestResponseBase.BodyInternal
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.BodyString - uid: Titanium.Web.Proxy.Http.RequestResponseBase.BodyString
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment