Unverified Commit 33bb3f08 authored by justcoding121's avatar justcoding121 Committed by GitHub

Merge pull request #472 from justcoding121/beta

Stable
parents 35cd23b6 30782eac
......@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
......@@ -14,7 +15,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
public class ProxyTestController
{
private readonly object lockObj = new object();
private readonly SemaphoreSlim @lock = new SemaphoreSlim(1);
private readonly ProxyServer proxyServer;
......@@ -23,16 +24,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
public ProxyTestController()
{
proxyServer = new ProxyServer();
proxyServer.EnableConnectionPool = true;
// generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
proxyServer.ExceptionFunc = exception =>
proxyServer.ExceptionFunc = async exception =>
{
lock (lockObj)
await @lock.WaitAsync();
try
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
......@@ -46,6 +49,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
Console.ForegroundColor = color;
}
finally
{
@lock.Release();
}
};
proxyServer.ForwardToUpstreamGateway = true;
......@@ -130,7 +138,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.WebSession.Request.RequestUri.Host;
WriteToConsole("Tunnel to: " + hostname);
await WriteToConsole("Tunnel to: " + hostname);
if (hostname.Contains("dropbox.com"))
{
......@@ -141,15 +149,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
}
private async Task OnBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
private Task OnBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{
return Task.FromResult(false);
}
// intecept & cancel redirect or update requests
private async Task OnRequest(object sender, SessionEventArgs e)
{
WriteToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
WriteToConsole(e.WebSession.Request.Url);
await WriteToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
await WriteToConsole(e.WebSession.Request.Url);
// store it in the UserData property
// It can be a simple integer, Guid, or any type
......@@ -187,19 +196,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
// Modify response
private void MultipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
private async Task MultipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
{
var session = (SessionEventArgs)sender;
WriteToConsole("Multipart form data headers:");
await WriteToConsole("Multipart form data headers:");
foreach (var header in e.Headers)
{
WriteToConsole(header.ToString());
await WriteToConsole(header.ToString());
}
}
private async Task OnResponse(object sender, SessionEventArgs e)
{
WriteToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
await WriteToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
string ext = System.IO.Path.GetExtension(e.WebSession.Request.RequestUri.AbsolutePath);
......@@ -271,12 +280,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
return Task.FromResult(0);
}
private void WriteToConsole(string message)
private async Task WriteToConsole(string message)
{
lock (lockObj)
await @lock.WaitAsync();
try
{
Console.WriteLine(message);
}
finally
{
@lock.Release();
}
}
///// <summary>
......
......@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="StreamExtended, Version=1.0.164.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.164\lib\net45\StreamExtended.dll</HintPath>
<Reference Include="StreamExtended, Version=1.0.179.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.179\lib\net45\StreamExtended.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StreamExtended" version="1.0.164" targetFramework="net45" />
<package id="StreamExtended" version="1.0.179" targetFramework="net45" />
</packages>
\ No newline at end of file
Doneness:
- [ ] Build is okay - I made sure that this change is building successfully.
- [ ] No Bugs - I made sure that this change is working properly as expected. It doesn't have any bugs that you are aware of.
- [ ] Branching - If this is not a hotfix, I am making this request against develop branch
- [ ] Branching - If this is not a hotfix, I am making this request against master branch
......@@ -19,12 +19,9 @@ Kindly report only issues/bugs here . For programming help or questions use [Sta
### Features
* Multithreaded & fully asynchronous proxy
* Supports HTTP(S) and most features of HTTP 1.1
* Supports redirect/block/update requests and modifying responses
* Safely relays Web Socket requests over HTTP
* Supports mutual SSL authentication
* Supports proxy authentication & automatic proxy detection
* Multithreaded & fully asynchronous proxy employing server connection pooling, certificate cache & buffer pooling
* View/modify/redirect/block requests & responses
* Supports mutual SSL authentication, proxy authentication & automatic upstream proxy detection
* Kerberos/NTLM authentication over HTTP protocols for windows domain
### Usage
......@@ -36,7 +33,7 @@ Install by [nuget](https://www.nuget.org/packages/Titanium.Web.Proxy)
For beta releases on [beta branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/beta)
Install-Package Titanium.Web.Proxy -Pre
Install-Package Titanium.Web.Proxy
For stable releases on [stable branch](https://github.com/justcoding121/Titanium-Web-Proxy/tree/stable)
......
......@@ -23,6 +23,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a4ab2e69_002D4d9c_002D4345_002Dbcd1_002D5541dacf5d38/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Method (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="METHOD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=dda2ffa1_002D435c_002D4111_002D88eb_002D1a7c93c382f0/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
......
......@@ -2,23 +2,25 @@
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended;
using StreamExtended.Network;
namespace Titanium.Web.Proxy.EventArguments
{
internal class LimitedStream : Stream
{
private readonly IBufferPool bufferPool;
private readonly ICustomStreamReader baseStream;
private readonly bool isChunked;
private long bytesRemaining;
private bool readChunkTrail;
internal LimitedStream(ICustomStreamReader baseStream, bool isChunked,
internal LimitedStream(ICustomStreamReader baseStream, IBufferPool bufferPool, bool isChunked,
long contentLength)
{
this.baseStream = baseStream;
this.bufferPool = bufferPool;
this.isChunked = isChunked;
bytesRemaining = isChunked
? 0
......@@ -41,7 +43,7 @@ namespace Titanium.Web.Proxy.EventArguments
set => throw new NotSupportedException();
}
private void GetNextChunk()
private void getNextChunk()
{
if (readChunkTrail)
{
......@@ -96,7 +98,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (isChunked)
{
GetNextChunk();
getNextChunk();
}
else
{
......@@ -125,7 +127,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (bytesRemaining != -1)
{
var buffer = BufferPool.GetBuffer(baseStream.BufferSize);
var buffer = bufferPool.GetBuffer(baseStream.BufferSize);
try
{
int res = await ReadAsync(buffer, 0, buffer.Length);
......@@ -136,7 +138,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
finally
{
BufferPool.ReturnBuffer(buffer);
bufferPool.ReturnBuffer(buffer);
}
}
}
......
......@@ -4,14 +4,12 @@ using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -33,15 +31,15 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, null, cancellationTokenSource, exceptionFunc)
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource)
: this(server, endPoint, null, cancellationTokenSource)
{
}
protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint,
Request request, CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, request, exceptionFunc)
protected SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint,
Request request, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, cancellationTokenSource, request)
{
}
......@@ -69,12 +67,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public event EventHandler<MultipartRequestPartSentEventArgs> MultipartRequestPartSent;
private ICustomStreamReader GetStreamReader(bool isRequest)
private ICustomStreamReader getStreamReader(bool isRequest)
{
return isRequest ? ProxyClient.ClientStream : WebSession.ServerConnection.Stream;
}
private HttpWriter GetStreamWriter(bool isRequest)
private HttpWriter getStreamWriter(bool isRequest)
{
return isRequest ? (HttpWriter)ProxyClient.ClientStreamWriter : WebSession.ServerConnection.StreamWriter;
}
......@@ -82,7 +80,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Read request body content as bytes[] for current session
/// </summary>
private async Task ReadRequestBodyAsync(CancellationToken cancellationToken)
private async Task readRequestBodyAsync(CancellationToken cancellationToken)
{
WebSession.Request.EnsureBodyAvailable(false);
......@@ -91,7 +89,7 @@ namespace Titanium.Web.Proxy.EventArguments
// If not already read (not cached yet)
if (!request.IsBodyRead)
{
var body = await ReadBodyAsync(true, cancellationToken);
var body = await readBodyAsync(true, cancellationToken);
request.Body = body;
// Now set the flag to true
......@@ -119,14 +117,14 @@ namespace Titanium.Web.Proxy.EventArguments
}
catch (Exception ex)
{
ExceptionFunc(new Exception("Exception thrown in user event", ex));
exceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
/// <summary>
/// Read response body as byte[] for current response
/// </summary>
private async Task ReadResponseBodyAsync(CancellationToken cancellationToken)
private async Task readResponseBodyAsync(CancellationToken cancellationToken)
{
if (!WebSession.Request.Locked)
{
......@@ -142,7 +140,7 @@ namespace Titanium.Web.Proxy.EventArguments
// If not already read (not cached yet)
if (!response.IsBodyRead)
{
var body = await ReadBodyAsync(false, cancellationToken);
var body = await readBodyAsync(false, cancellationToken);
response.Body = body;
// Now set the flag to true
......@@ -152,11 +150,11 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
private async Task<byte[]> ReadBodyAsync(bool isRequest, CancellationToken cancellationToken)
private async Task<byte[]> readBodyAsync(bool isRequest, CancellationToken cancellationToken)
{
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, BufferSize);
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize);
if (isRequest)
{
......@@ -171,18 +169,25 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
/// <summary>
/// Syphon out any left over data in given request/response from backing tcp connection.
/// When user modifies the response/request we need to do this to reuse tcp connections.
/// </summary>
/// <param name="isRequest"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken)
{
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
if (requestResponse.IsBodyRead || !requestResponse.OriginalHasBody)
if (requestResponse.OriginalIsBodyRead || !requestResponse.OriginalHasBody)
{
return;
}
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, BufferSize);
await CopyBodyAsync(isRequest, writer, TransformationMode.None, null, cancellationToken);
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize);
await copyBodyAsync(isRequest, true, writer, TransformationMode.None, null, cancellationToken);
}
}
......@@ -199,14 +204,14 @@ namespace Titanium.Web.Proxy.EventArguments
// send the request body bytes to server
if (contentLength > 0 && hasMulipartEventSubscribers && request.IsMultipartFormData)
{
var reader = GetStreamReader(true);
var reader = getStreamReader(true);
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
using (var copyStream = new CopyStream(reader, writer, BufferSize))
using (var copyStream = new CopyStream(reader, writer, bufferPool, bufferSize))
{
while (contentLength > copyStream.ReadBytes)
{
long read = await ReadUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken);
long read = await readUntilBoundaryAsync(copyStream, contentLength, boundary, cancellationToken);
if (read == 0)
{
break;
......@@ -225,23 +230,24 @@ namespace Titanium.Web.Proxy.EventArguments
}
else
{
await CopyBodyAsync(true, writer, transformation, OnDataSent, cancellationToken);
await copyBodyAsync(true, false, writer, transformation, OnDataSent, cancellationToken);
}
}
internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken)
{
await CopyBodyAsync(false, writer, transformation, OnDataReceived, cancellationToken);
await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken);
}
private async Task CopyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{
var stream = GetStreamReader(isRequest);
var stream = getStreamReader(isRequest);
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
bool isChunked = requestResponse.IsChunked;
long contentLength = requestResponse.ContentLength;
bool isChunked = useOriginalHeaderValues? requestResponse.OriginalIsChunked : requestResponse.IsChunked;
long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength;
if (transformation == TransformationMode.None)
{
await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken);
......@@ -251,9 +257,9 @@ namespace Titanium.Web.Proxy.EventArguments
LimitedStream limitedStream;
Stream decompressStream = null;
string contentEncoding = requestResponse.ContentEncoding;
string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, isChunked, contentLength);
Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength);
if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{
......@@ -262,7 +268,7 @@ namespace Titanium.Web.Proxy.EventArguments
try
{
using (var bufStream = new CustomBufferedStream(s, BufferSize, true))
using (var bufStream = new CustomBufferedStream(s, bufferPool, bufferSize, true))
{
await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken);
}
......@@ -280,11 +286,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// Read a line from the byte stream
/// </summary>
/// <returns></returns>
private async Task<long> ReadUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken)
private async Task<long> readUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken)
{
int bufferDataLength = 0;
var buffer = BufferPool.GetBuffer(BufferSize);
var buffer = bufferPool.GetBuffer(bufferSize);
try
{
int boundaryLength = boundary.Length + 4;
......@@ -334,7 +340,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
finally
{
BufferPool.ReturnBuffer(buffer);
bufferPool.ReturnBuffer(buffer);
}
}
......@@ -347,7 +353,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Request.IsBodyRead)
{
await ReadRequestBodyAsync(cancellationToken);
await readRequestBodyAsync(cancellationToken);
}
return WebSession.Request.Body;
......@@ -362,7 +368,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Request.IsBodyRead)
{
await ReadRequestBodyAsync(cancellationToken);
await readRequestBodyAsync(cancellationToken);
}
return WebSession.Request.BodyString;
......@@ -407,7 +413,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Response.IsBodyRead)
{
await ReadResponseBodyAsync(cancellationToken);
await readResponseBodyAsync(cancellationToken);
}
return WebSession.Response.Body;
......@@ -422,7 +428,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Response.IsBodyRead)
{
await ReadResponseBodyAsync(cancellationToken);
await readResponseBodyAsync(cancellationToken);
}
return WebSession.Response.BodyString;
......@@ -465,7 +471,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// <param name="html">HTML content to sent.</param>
/// <param name="headers">HTTP response headers.</param>
public void Ok(string html, Dictionary<string, HttpHeader> headers = null)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Ok(string html, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false)
{
var response = new OkResponse();
if (headers != null)
......@@ -476,7 +484,7 @@ namespace Titanium.Web.Proxy.EventArguments
response.HttpVersion = WebSession.Request.HttpVersion;
response.Body = response.Encoding.GetBytes(html ?? string.Empty);
Respond(response);
Respond(response, closeServerConnection);
}
/// <summary>
......@@ -485,14 +493,16 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// <param name="result">The html content bytes.</param>
/// <param name="headers">The HTTP headers.</param>
public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false)
{
var response = new OkResponse();
response.Headers.AddHeaders(headers);
response.HttpVersion = WebSession.Request.HttpVersion;
response.Body = result;
Respond(response);
Respond(response, closeServerConnection);
}
/// <summary>
......@@ -503,15 +513,16 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="html">The html content.</param>
/// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</param>
/// <returns></returns>
public void GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void GenericResponse(string html, HttpStatusCode status,
Dictionary<string, HttpHeader> headers = null, bool closeServerConnection = false)
{
var response = new GenericResponse(status);
response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeaders(headers);
response.Body = response.Encoding.GetBytes(html ?? string.Empty);
Respond(response);
Respond(response, closeServerConnection);
}
/// <summary>
......@@ -521,66 +532,82 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="result">The bytes to sent.</param>
/// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</param>
/// <returns></returns>
public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void GenericResponse(byte[] result, HttpStatusCode status,
Dictionary<string, HttpHeader> headers, bool closeServerConnection = false)
{
var response = new GenericResponse(status);
response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeaders(headers);
response.Body = result;
Respond(response);
Respond(response, closeServerConnection);
}
/// <summary>
/// Redirect to provided URL.
/// </summary>
/// <param name="url">The URL to redirect.</param>
/// <returns></returns>
public void Redirect(string url)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Redirect(string url, bool closeServerConnection = false)
{
var response = new RedirectResponse();
response.HttpVersion = WebSession.Request.HttpVersion;
response.Headers.AddHeader(KnownHeaders.Location, url);
response.Body = emptyData;
Respond(response);
Respond(response, closeServerConnection);
}
/// <summary>
/// Respond with given response object to client.
/// </summary>
/// <param name="response">The response object.</param>
public void Respond(Response response)
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Respond(Response response, bool closeServerConnection = false)
{
//request already send/ready to be sent.
if (WebSession.Request.Locked)
{
//response already received from server and ready to be sent to client.
if (WebSession.Response.Locked)
{
throw new Exception("You cannot call this function after response is sent to the client.");
}
response.Locked = true;
response.TerminateResponse = WebSession.Response.TerminateResponse;
//cleanup original response.
if (closeServerConnection)
{
//no need to cleanup original connection.
//it will be closed any way.
TerminateServerConnection();
}
response.SetOriginalHeaders(WebSession.Response);
//response already received from server but not yet ready to sent to client.
WebSession.Response = response;
WebSession.Response.Locked = true;
}
//request not yet sent/not yet ready to be sent.
else
{
WebSession.Request.Locked = true;
WebSession.Request.CancelRequest = true;
response.Locked = true;
//set new response.
WebSession.Response = response;
WebSession.Request.CancelRequest = true;
WebSession.Response.Locked = true;
}
}
/// <summary>
/// Terminate the connection to server.
/// Terminate the connection to server at the end of this HTTP request/response session.
/// </summary>
public void TerminateServerConnection()
{
WebSession.Response.TerminateResponse = true;
WebSession.CloseServerConnection = true;
}
/// <summary>
......
using System;
using System.Net;
using System.Threading;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
......@@ -17,34 +18,32 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public abstract class SessionEventArgsBase : EventArgs, IDisposable
{
/// <summary>
/// Size of Buffers used by this object
/// </summary>
protected readonly int BufferSize;
internal readonly CancellationTokenSource CancellationTokenSource;
protected readonly ExceptionHandler ExceptionFunc;
protected readonly int bufferSize;
protected readonly IBufferPool bufferPool;
protected readonly ExceptionHandler exceptionFunc;
/// <summary>
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
private SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource)
{
bufferSize = server.BufferSize;
bufferPool = server.BufferPool;
exceptionFunc = server.ExceptionFunc;
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource,
Request request, ExceptionHandler exceptionFunc)
Request request) : this(server, endPoint, cancellationTokenSource)
{
BufferSize = bufferSize;
ExceptionFunc = exceptionFunc;
CancellationTokenSource = cancellationTokenSource;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
WebSession = new HttpWebClient(request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() =>
......@@ -151,7 +150,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
catch (Exception ex)
{
ExceptionFunc(new Exception("Exception thrown in user event", ex));
exceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
......@@ -163,7 +162,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
catch (Exception ex)
{
ExceptionFunc(new Exception("Exception thrown in user event", ex));
exceptionFunc(new Exception("Exception thrown in user event", ex));
}
}
......
......@@ -12,9 +12,9 @@ namespace Titanium.Web.Proxy.EventArguments
{
private bool? isHttpsConnect;
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
internal TunnelConnectSessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, ConnectRequest connectRequest,
CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, cancellationTokenSource, connectRequest)
{
WebSession.ConnectRequest = connectRequest;
}
......
using System;
namespace Titanium.Web.Proxy.Exceptions
{
/// <summary>
/// The server connection was closed upon first read with the new connection from pool.
/// Should retry the request with a new connection.
/// </summary>
public class ServerConnectionException : ProxyException
{
internal ServerConnectionException(string message) : base(message)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="message"></param>
/// <param name="e"></param>
internal ServerConnectionException(string message, Exception e) : base(message, e)
{
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
......@@ -7,15 +8,14 @@ using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http2;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy
......@@ -29,20 +29,24 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint">The explicit endpoint.</param>
/// <param name="clientConnection">The client connection.</param>
/// <returns>The task.</returns>
private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferSize);
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
Task<TcpServerConnection> prefetchConnectionTask = null;
bool closeServerConnection = false;
bool calledRequestHandler = false;
try
{
string connectHostname = null;
TunnelConnectSessionEventArgs connectArgs = null;
// Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
if (await HttpHelper.IsConnectMethod(clientStream) == 1)
{
......@@ -67,8 +71,8 @@ namespace Titanium.Web.Proxy
await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest,
cancellationTokenSource, ExceptionFunc);
connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest,
cancellationTokenSource);
connectArgs.ProxyClient.ClientConnection = clientConnection;
connectArgs.ProxyClient.ClientStream = clientStream;
......@@ -95,7 +99,7 @@ namespace Titanium.Web.Proxy
return;
}
if (await CheckAuthorization(connectArgs) == false)
if (await checkAuthorization(connectArgs) == false)
{
await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc);
......@@ -115,7 +119,7 @@ namespace Titanium.Web.Proxy
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationToken);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
bool isClientHello = clientHelloInfo != null;
if (isClientHello)
......@@ -129,21 +133,31 @@ namespace Titanium.Web.Proxy
{
connectRequest.RequestUri = new Uri("https://" + httpUrl);
bool http2Supproted = false;
bool http2Supported = false;
var alpn = clientHelloInfo.GetAlpn();
if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2))
{
// test server HTTP/2 support
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
using (var connection = await GetServerConnection(connectArgs, true, SslExtensions.Http2ProtocolAsList, cancellationToken))
{
http2Supproted = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2;
}
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: SslExtensions.Http2ProtocolAsList,
noCache: true, cancellationToken: cancellationToken);
http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2;
//release connection back to pool intead of closing when connection pool is enabled.
await tcpConnectionFactory.Release(connection, true);
}
SslStream sslStream = null;
//don't pass cancellation token here
//it could cause floating server connections when client exits
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: null, noCache: false,
cancellationToken: CancellationToken.None);
try
{
sslStream = new SslStream(clientStream);
......@@ -155,7 +169,7 @@ namespace Titanium.Web.Proxy
// Successfully managed to authenticate the client using the fake certificate
var options = new SslServerAuthenticationOptions();
if (http2Supproted)
if (http2Supported)
{
options.ApplicationProtocols = clientHelloInfo.GetAlpn();
if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
......@@ -175,9 +189,8 @@ namespace Titanium.Web.Proxy
#endif
// HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
}
catch (Exception e)
{
......@@ -190,6 +203,12 @@ namespace Titanium.Web.Proxy
{
decryptSsl = false;
}
if(!decryptSsl)
{
await tcpConnectionFactory.Release(prefetchConnectionTask, true);
prefetchConnectionTask = null;
}
}
if (cancellationTokenSource.IsCancellationRequested)
......@@ -200,8 +219,14 @@ namespace Titanium.Web.Proxy
// Hostname is excluded or it is not an HTTPS connect
if (!decryptSsl || !isClientHello)
{
// create new connection
using (var connection = await GetServerConnection(connectArgs, true, clientConnection.NegotiatedApplicationProtocol, cancellationToken))
// create new connection to server.
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
// this connection should not be HTTPS.
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: SslExtensions.Http2ProtocolAsList,
noCache: true, cancellationToken: cancellationToken);
try
{
if (isClientHello)
{
......@@ -213,10 +238,9 @@ namespace Titanium.Web.Proxy
try
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await clientStream.ReadAsync(data, 0, available, cancellationToken);
await connection.StreamWriter.WriteAsync(data, 0, available, true,
cancellationToken);
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken);
}
finally
{
......@@ -224,16 +248,19 @@ namespace Titanium.Web.Proxy
}
}
var serverHelloInfo =
await SslTools.PeekServerHello(connection.Stream, cancellationToken);
var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken);
((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
}
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
connectArgs.CancellationTokenSource, ExceptionFunc);
}
finally
{
await tcpConnectionFactory.Release(connection, true);
}
return;
}
......@@ -264,47 +291,64 @@ namespace Titanium.Web.Proxy
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
}
// create new connection
using (var connection = await GetServerConnection(connectArgs, true, SslExtensions.Http2ProtocolAsList, cancellationToken))
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
isConnect: true, applicationProtocols: SslExtensions.Http2ProtocolAsList,
noCache: true, cancellationToken: cancellationToken);
try
{
await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken);
await connection.StreamWriter.WriteLineAsync("SM", cancellationToken);
await connection.StreamWriter.WriteLineAsync(cancellationToken);
#if NETCOREAPP2_1
await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc);
#endif
}
finally
{
await tcpConnectionFactory.Release(connection, true);
}
}
}
calledRequestHandler = true;
// Now create the request
await HandleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, connectHostname, connectArgs?.WebSession.ConnectRequest);
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, connectHostname, connectArgs?.WebSession.ConnectRequest, prefetchConnectionTask);
}
catch (ProxyException e)
{
OnException(clientStream, e);
closeServerConnection = true;
onException(clientStream, e);
}
catch (IOException e)
{
OnException(clientStream, new Exception("Connection was aborted", e));
closeServerConnection = true;
onException(clientStream, new Exception("Connection was aborted", e));
}
catch (SocketException e)
{
OnException(clientStream, new Exception("Could not connect", e));
closeServerConnection = true;
onException(clientStream, new Exception("Could not connect", e));
}
catch (Exception e)
{
OnException(clientStream, new Exception("Error occured in whilst handling the client", e));
closeServerConnection = true;
onException(clientStream, new Exception("Error occured in whilst handling the client", e));
}
finally
{
if (!calledRequestHandler)
{
await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
}
clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested)
{
cancellationTokenSource.Cancel();
......
......@@ -13,11 +13,11 @@ namespace Titanium.Web.Proxy.Extensions
foreach (var @delegate in invocationList)
{
await InternalInvokeAsync((AsyncEventHandler<T>)@delegate, sender, args, exceptionFunc);
await internalInvokeAsync((AsyncEventHandler<T>)@delegate, sender, args, exceptionFunc);
}
}
private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args,
private static async Task internalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args,
ExceptionHandler exceptionFunc)
{
try
......
......@@ -2,7 +2,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended;
namespace Titanium.Web.Proxy.Extensions
{
......@@ -19,9 +19,9 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="onCopy"></param>
/// <param name="bufferSize"></param>
internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize)
IBufferPool bufferPool, int bufferSize)
{
return CopyToAsync(input, output, onCopy, bufferSize, CancellationToken.None);
return CopyToAsync(input, output, onCopy, bufferPool, bufferSize, CancellationToken.None);
}
/// <summary>
......@@ -33,9 +33,9 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="bufferSize"></param>
/// <param name="cancellationToken"></param>
internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, CancellationToken cancellationToken)
IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken)
{
var buffer = BufferPool.GetBuffer(bufferSize);
var buffer = bufferPool.GetBuffer(bufferSize);
try
{
while (!cancellationToken.IsCancellationRequested)
......@@ -43,7 +43,7 @@ namespace Titanium.Web.Proxy.Extensions
// cancellation is not working on Socket ReadAsync
// https://github.com/dotnet/corefx/issues/15033
int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None)
.WithCancellation(cancellationToken);
.withCancellation(cancellationToken);
int bytesRead;
if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested)
{
......@@ -58,11 +58,11 @@ namespace Titanium.Web.Proxy.Extensions
}
finally
{
BufferPool.ReturnBuffer(buffer);
bufferPool.ReturnBuffer(buffer);
}
}
private static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
private static async Task<T> withCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
......
......@@ -122,7 +122,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader)
{
return StartsWith(clientStreamReader, "CONNECT");
return startsWith(clientStreamReader, "CONNECT");
}
/// <summary>
......@@ -132,7 +132,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader)
{
return StartsWith(clientStreamReader, "PRI");
return startsWith(clientStreamReader, "PRI");
}
/// <summary>
......@@ -143,7 +143,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
private static async Task<int> StartsWith(ICustomStreamReader clientStreamReader, string expectedStart)
private static async Task<int> startsWith(ICustomStreamReader clientStreamReader, string expectedStart)
{
bool isExpected = true;
int legthToCheck = 10;
......
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers
{
internal sealed class HttpRequestWriter : HttpWriter
{
internal HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
internal HttpRequestWriter(Stream stream, IBufferPool bufferPool, int bufferSize)
: base(stream, bufferPool, bufferSize)
{
}
......
......@@ -2,13 +2,15 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers
{
internal sealed class HttpResponseWriter : HttpWriter
{
internal HttpResponseWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
internal HttpResponseWriter(Stream stream, IBufferPool bufferPool, int bufferSize)
: base(stream, bufferPool, bufferSize)
{
}
......
......@@ -4,7 +4,7 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared;
......@@ -14,6 +14,7 @@ namespace Titanium.Web.Proxy.Helpers
internal class HttpWriter : ICustomStreamWriter
{
private readonly Stream stream;
private readonly IBufferPool bufferPool;
private static readonly byte[] newLine = ProxyConstants.NewLine;
......@@ -21,10 +22,11 @@ namespace Titanium.Web.Proxy.Helpers
private readonly char[] charBuffer;
internal HttpWriter(Stream stream, int bufferSize)
internal HttpWriter(Stream stream, IBufferPool bufferPool, int bufferSize)
{
BufferSize = bufferSize;
this.stream = stream;
this.bufferPool = bufferPool;
// ASCII encoder max byte count is char count + 1
charBuffer = new char[BufferSize - 1];
......@@ -44,10 +46,10 @@ namespace Titanium.Web.Proxy.Helpers
internal Task WriteAsync(string value, CancellationToken cancellationToken = default)
{
return WriteAsyncInternal(value, false, cancellationToken);
return writeAsyncInternal(value, false, cancellationToken);
}
private Task WriteAsyncInternal(string value, bool addNewLine, CancellationToken cancellationToken)
private Task writeAsyncInternal(string value, bool addNewLine, CancellationToken cancellationToken)
{
int newLineChars = addNewLine ? newLine.Length : 0;
int charCount = value.Length;
......@@ -55,7 +57,7 @@ namespace Titanium.Web.Proxy.Helpers
{
value.CopyTo(0, charBuffer, 0, charCount);
var buffer = BufferPool.GetBuffer(BufferSize);
var buffer = bufferPool.GetBuffer(BufferSize);
try
{
int idx = encoder.GetBytes(charBuffer, 0, charCount, buffer, 0, true);
......@@ -69,7 +71,7 @@ namespace Titanium.Web.Proxy.Helpers
}
finally
{
BufferPool.ReturnBuffer(buffer);
bufferPool.ReturnBuffer(buffer);
}
}
else
......@@ -91,7 +93,7 @@ namespace Titanium.Web.Proxy.Helpers
internal Task WriteLineAsync(string value, CancellationToken cancellationToken = default)
{
return WriteAsyncInternal(value, true, cancellationToken);
return writeAsyncInternal(value, true, cancellationToken);
}
/// <summary>
......@@ -104,12 +106,15 @@ namespace Titanium.Web.Proxy.Helpers
internal async Task WriteHeadersAsync(HeaderCollection headers, bool flush = true,
CancellationToken cancellationToken = default)
{
var headerBuilder = new StringBuilder();
foreach (var header in headers)
{
await header.WriteToStreamAsync(this, cancellationToken);
headerBuilder.AppendLine(header.ToString());
}
headerBuilder.AppendLine();
await WriteAsync(headerBuilder.ToString(), cancellationToken);
await WriteLineAsync(cancellationToken);
if (flush)
{
await stream.FlushAsync(cancellationToken);
......@@ -146,7 +151,7 @@ namespace Titanium.Web.Proxy.Helpers
{
if (isChunked)
{
return WriteBodyChunkedAsync(data, cancellationToken);
return writeBodyChunkedAsync(data, cancellationToken);
}
return WriteAsync(data, cancellationToken: cancellationToken);
......@@ -168,7 +173,7 @@ namespace Titanium.Web.Proxy.Helpers
// For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (isChunked)
{
return CopyBodyChunkedAsync(streamReader, onCopy, cancellationToken);
return copyBodyChunkedAsync(streamReader, onCopy, cancellationToken);
}
// http 1.0 or the stream reader limits the stream
......@@ -178,7 +183,7 @@ namespace Titanium.Web.Proxy.Helpers
}
// 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);
}
/// <summary>
......@@ -187,7 +192,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="data"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task WriteBodyChunkedAsync(byte[] data, CancellationToken cancellationToken)
private async Task writeBodyChunkedAsync(byte[] data, CancellationToken cancellationToken)
{
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
......@@ -207,7 +212,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task CopyBodyChunkedAsync(ICustomStreamReader reader, Action<byte[], int, int> onCopy,
private async Task copyBodyChunkedAsync(ICustomStreamReader reader, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken)
{
while (true)
......@@ -225,7 +230,7 @@ namespace Titanium.Web.Proxy.Helpers
if (chunkSize != 0)
{
await CopyBytesFromStream(reader, chunkSize, onCopy, cancellationToken);
await copyBytesFromStream(reader, chunkSize, onCopy, cancellationToken);
}
await WriteLineAsync(cancellationToken);
......@@ -248,10 +253,10 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="onCopy"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task CopyBytesFromStream(ICustomStreamReader reader, long count, Action<byte[], int, int> onCopy,
private async Task copyBytesFromStream(ICustomStreamReader reader, long count, Action<byte[], int, int> onCopy,
CancellationToken cancellationToken)
{
var buffer = BufferPool.GetBuffer(BufferSize);
var buffer = bufferPool.GetBuffer(BufferSize);
try
{
......@@ -280,7 +285,7 @@ namespace Titanium.Web.Proxy.Helpers
}
finally
{
BufferPool.ReturnBuffer(buffer);
bufferPool.ReturnBuffer(buffer);
}
}
......
......@@ -28,36 +28,44 @@ namespace Titanium.Web.Proxy.Helpers
internal static bool IsLocalIpAddress(string hostName)
{
bool isLocalhost = false;
hostName = hostName.ToLower();
var localhost = Dns.GetHostEntry("127.0.0.1");
if (hostName == localhost.HostName)
if (hostName == "127.0.0.1"
|| hostName == "localhost")
{
var hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = hostEntry.AddressList.Any(IPAddress.IsLoopback);
return true;
}
if (!isLocalhost)
var localhostDnsName = Dns.GetHostName().ToLower();
//if hostname matches current machine DNS name
if (hostName == localhostDnsName)
{
localhost = Dns.GetHostEntry(Dns.GetHostName());
return true;
}
var isLocalhost = false;
IPHostEntry hostEntry = null;
//check if parsable to an IP Address
if (IPAddress.TryParse(hostName, out var ipAddress))
{
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
hostEntry = Dns.GetHostEntry(localhostDnsName);
isLocalhost = hostEntry.AddressList.Any(x => x.Equals(ipAddress));
}
if (!isLocalhost)
{
try
{
var hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = localhost.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals));
hostEntry = Dns.GetHostEntry(hostName);
isLocalhost = hostEntry.AddressList.Any(x => hostEntry.AddressList.Any(x.Equals));
}
catch (SocketException)
{
}
}
}
return isLocalhost;
}
......
......@@ -39,7 +39,7 @@ namespace Titanium.Web.Proxy.Helpers
}
else
{
overrides2.Add(BypassStringEscape(overrideHost));
overrides2.Add(bypassStringEscape(overrideHost));
}
}
......@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Helpers
internal string[] BypassList { get; }
private static string BypassStringEscape(string rawString)
private static string bypassStringEscape(string rawString)
{
var match =
new Regex("^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$",
......@@ -91,9 +91,9 @@ namespace Titanium.Web.Proxy.Helpers
empty2 = string.Empty;
}
string str1 = ConvertRegexReservedChars(empty1);
string str2 = ConvertRegexReservedChars(rawString1);
string str3 = ConvertRegexReservedChars(empty2);
string str1 = convertRegexReservedChars(empty1);
string str2 = convertRegexReservedChars(rawString1);
string str3 = convertRegexReservedChars(empty2);
if (str1 == string.Empty)
{
str1 = "(?:.*://)?";
......@@ -107,7 +107,7 @@ namespace Titanium.Web.Proxy.Helpers
return "^" + str1 + str2 + str3 + "$";
}
private static string ConvertRegexReservedChars(string rawString)
private static string convertRegexReservedChars(string rawString)
{
if (rawString.Length == 0)
{
......@@ -171,11 +171,11 @@ namespace Titanium.Web.Proxy.Helpers
if (proxyValues.Length > 0)
{
result.AddRange(proxyValues.Select(ParseProxyValue).Where(parsedValue => parsedValue != null));
result.AddRange(proxyValues.Select(parseProxyValue).Where(parsedValue => parsedValue != null));
}
else
{
var parsedValue = ParseProxyValue(proxyServerValues);
var parsedValue = parseProxyValue(proxyServerValues);
if (parsedValue != null)
{
result.Add(parsedValue);
......@@ -190,7 +190,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static HttpSystemProxyValue ParseProxyValue(string value)
private static HttpSystemProxyValue parseProxyValue(string value)
{
string tmp = Regex.Replace(value, @"\s+", " ").Trim();
......
......@@ -84,8 +84,8 @@ namespace Titanium.Web.Proxy.Helpers
if (reg != null)
{
SaveOriginalProxyConfiguration(reg);
PrepareRegistry(reg);
saveOriginalProxyConfiguration(reg);
prepareRegistry(reg);
string exisitingContent = reg.GetValue(regProxyServer) as string;
var existingSystemProxyValues = ProxyInfo.GetSystemProxyValues(exisitingContent);
......@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy.Helpers
reg.SetValue(regProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
Refresh();
refresh();
}
}
......@@ -129,7 +129,7 @@ namespace Titanium.Web.Proxy.Helpers
{
if (saveOriginalConfig)
{
SaveOriginalProxyConfiguration(reg);
saveOriginalProxyConfiguration(reg);
}
if (reg.GetValue(regProxyServer) != null)
......@@ -152,7 +152,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
Refresh();
refresh();
}
}
......@@ -165,12 +165,12 @@ namespace Titanium.Web.Proxy.Helpers
if (reg != null)
{
SaveOriginalProxyConfiguration(reg);
saveOriginalProxyConfiguration(reg);
reg.SetValue(regProxyEnable, 0);
reg.SetValue(regProxyServer, string.Empty);
Refresh();
refresh();
}
}
......@@ -180,9 +180,9 @@ namespace Titanium.Web.Proxy.Helpers
if (reg != null)
{
SaveOriginalProxyConfiguration(reg);
saveOriginalProxyConfiguration(reg);
reg.SetValue(regAutoConfigUrl, url);
Refresh();
refresh();
}
}
......@@ -192,9 +192,9 @@ namespace Titanium.Web.Proxy.Helpers
if (reg != null)
{
SaveOriginalProxyConfiguration(reg);
saveOriginalProxyConfiguration(reg);
reg.SetValue(regProxyOverride, proxyOverride);
Refresh();
refresh();
}
}
......@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers
}
originalValues = null;
Refresh();
refresh();
}
}
......@@ -257,13 +257,13 @@ namespace Titanium.Web.Proxy.Helpers
if (reg != null)
{
return GetProxyInfoFromRegistry(reg);
return getProxyInfoFromRegistry(reg);
}
return null;
}
private ProxyInfo GetProxyInfoFromRegistry(RegistryKey reg)
private ProxyInfo getProxyInfoFromRegistry(RegistryKey reg)
{
var pi = new ProxyInfo(null, reg.GetValue(regAutoConfigUrl) as string, reg.GetValue(regProxyEnable) as int?,
reg.GetValue(regProxyServer) as string,
......@@ -272,21 +272,21 @@ namespace Titanium.Web.Proxy.Helpers
return pi;
}
private void SaveOriginalProxyConfiguration(RegistryKey reg)
private void saveOriginalProxyConfiguration(RegistryKey reg)
{
if (originalValues != null)
{
return;
}
originalValues = GetProxyInfoFromRegistry(reg);
originalValues = getProxyInfoFromRegistry(reg);
}
/// <summary>
/// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary>
/// <param name="reg"></param>
private static void PrepareRegistry(RegistryKey reg)
private static void prepareRegistry(RegistryKey reg)
{
if (reg.GetValue(regProxyEnable) == null)
{
......@@ -302,7 +302,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Refresh the settings so that the system know about a change in proxy setting
/// </summary>
private void Refresh()
private static void refresh()
{
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0);
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0);
......
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Helpers
......@@ -39,7 +37,7 @@ namespace Titanium.Web.Proxy.Helpers
0) == 0)
{
int rowCount = *(int*)tcpTable;
uint portInNetworkByteOrder = ToNetworkByteOrder((uint)localPort);
uint portInNetworkByteOrder = toNetworkByteOrder((uint)localPort);
if (ipVersion == IpVersion.Ipv4)
{
......@@ -90,7 +88,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
private static uint ToNetworkByteOrder(uint port)
private static uint toNetworkByteOrder(uint port)
{
return ((port >> 8) & 0x00FF00FFu) | ((port << 8) & 0xFF00FF00u);
}
......@@ -109,7 +107,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize,
internal static async Task SendRawApm(Stream clientStream, Stream serverStream,
IBufferPool bufferPool, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
......@@ -118,23 +117,23 @@ namespace Titanium.Web.Proxy.Helpers
cancellationTokenSource.Token.Register(() => taskCompletionSource.TrySetResult(true));
// Now async relay all server=>client & client=>server data
var clientBuffer = BufferPool.GetBuffer(bufferSize);
var serverBuffer = BufferPool.GetBuffer(bufferSize);
var clientBuffer = bufferPool.GetBuffer(bufferSize);
var serverBuffer = bufferPool.GetBuffer(bufferSize);
try
{
BeginRead(clientStream, serverStream, clientBuffer, onDataSend, cancellationTokenSource, exceptionFunc);
BeginRead(serverStream, clientStream, serverBuffer, onDataReceive, cancellationTokenSource,
beginRead(clientStream, serverStream, clientBuffer, onDataSend, cancellationTokenSource, exceptionFunc);
beginRead(serverStream, clientStream, serverBuffer, onDataReceive, cancellationTokenSource,
exceptionFunc);
await taskCompletionSource.Task;
}
finally
{
BufferPool.ReturnBuffer(clientBuffer);
BufferPool.ReturnBuffer(serverBuffer);
bufferPool.ReturnBuffer(clientBuffer);
bufferPool.ReturnBuffer(serverBuffer);
}
}
private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer,
private static void beginRead(Stream inputStream, Stream outputStream, byte[] buffer,
Action<byte[], int, int> onCopy, CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
{
......@@ -174,7 +173,7 @@ namespace Titanium.Web.Proxy.Helpers
try
{
outputStream.EndWrite(ar2);
BeginRead(inputStream, outputStream, buffer, onCopy, cancellationTokenSource,
beginRead(inputStream, outputStream, buffer, onCopy, cancellationTokenSource,
exceptionFunc);
}
catch (IOException ex)
......@@ -214,16 +213,17 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
private static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize,
private static async Task sendRawTap(Stream clientStream, Stream serverStream,
IBufferPool bufferPool, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
{
// Now async relay all server=>client & client=>server data
var sendRelay =
clientStream.CopyToAsync(serverStream, onDataSend, bufferSize, cancellationTokenSource.Token);
clientStream.CopyToAsync(serverStream, onDataSend, bufferPool, bufferSize, cancellationTokenSource.Token);
var receiveRelay =
serverStream.CopyToAsync(clientStream, onDataReceive, bufferSize, cancellationTokenSource.Token);
serverStream.CopyToAsync(clientStream, onDataReceive, bufferPool, bufferSize, cancellationTokenSource.Token);
await Task.WhenAny(sendRelay, receiveRelay);
cancellationTokenSource.Cancel();
......@@ -244,13 +244,14 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="cancellationTokenSource"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
internal static Task SendRaw(Stream clientStream, Stream serverStream,
IBufferPool bufferPool, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource,
ExceptionHandler exceptionFunc)
{
// todo: fix APM mode
return SendRawTap(clientStream, serverStream, bufferSize, onDataSend, onDataReceive,
return sendRawTap(clientStream, serverStream, bufferPool, bufferSize, onDataSend, onDataReceive,
cancellationTokenSource,
exceptionFunc);
}
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
session = NativeMethods.WinHttp.WinHttpOpen(null, NativeMethods.WinHttp.AccessType.NoProxy, null, null, 0);
if (session == null || session.IsInvalid)
{
int lastWin32Error = GetLastWin32Error();
int lastWin32Error = getLastWin32Error();
}
else
{
......@@ -30,7 +30,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return;
}
int lastWin32Error = GetLastWin32Error();
int lastWin32Error = getLastWin32Error();
}
}
......@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
public void Dispose()
{
Dispose(true);
dispose(true);
}
public bool GetAutoProxies(Uri destination, out IList<string> proxyList)
......@@ -65,8 +65,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed;
if (AutomaticallyDetectSettings && !autoDetectFailed)
{
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, null, out proxyListString);
autoDetectFailed = IsErrorFatalForAutoDetect(errorCode);
errorCode = (NativeMethods.WinHttp.ErrorCodes)getAutoProxies(destination, null, out proxyListString);
autoDetectFailed = isErrorFatalForAutoDetect(errorCode);
if (errorCode == NativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme)
{
state = AutoWebProxyState.UnrecognizedScheme;
......@@ -74,13 +74,13 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
}
}
if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode))
if (AutomaticConfigurationScript != null && isRecoverableAutoProxyError(errorCode))
{
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, AutomaticConfigurationScript,
errorCode = (NativeMethods.WinHttp.ErrorCodes)getAutoProxies(destination, AutomaticConfigurationScript,
out proxyListString);
}
state = GetStateFromErrorCode(errorCode);
state = getStateFromErrorCode(errorCode);
if (state != AutoWebProxyState.Completed)
{
return false;
......@@ -88,7 +88,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
if (!string.IsNullOrEmpty(proxyListString))
{
proxyListString = RemoveWhitespaces(proxyListString);
proxyListString = removeWhitespaces(proxyListString);
proxyList = proxyListString.Split(';');
}
......@@ -149,7 +149,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
public void LoadFromIE()
{
var pi = GetProxyInfo();
var pi = getProxyInfo();
ProxyInfo = pi;
AutomaticallyDetectSettings = pi.AutoDetect == true;
AutomaticConfigurationScript = pi.AutoConfigUrl == null ? null : new Uri(pi.AutoConfigUrl);
......@@ -158,7 +158,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
proxy = new WebProxy(new Uri("http://localhost"), BypassOnLocal, pi.BypassList);
}
private ProxyInfo GetProxyInfo()
private ProxyInfo getProxyInfo()
{
var proxyConfig = new NativeMethods.WinHttp.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG();
RuntimeHelpers.PrepareConstrainedRegions();
......@@ -200,7 +200,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
autoDetectFailed = false;
}
private void Dispose(bool disposing)
private void dispose(bool disposing)
{
if (!disposing || session == null || session.IsInvalid)
{
......@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
session.Close();
}
private int GetAutoProxies(Uri destination, Uri scriptLocation, out string proxyListString)
private int getAutoProxies(Uri destination, Uri scriptLocation, out string proxyListString)
{
int num = 0;
var autoProxyOptions = new NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS();
......@@ -229,16 +229,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
autoProxyOptions.AutoDetectFlags = NativeMethods.WinHttp.AutoDetectType.None;
}
if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
if (!winHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
{
num = GetLastWin32Error();
num = getLastWin32Error();
if (num == (int)NativeMethods.WinHttp.ErrorCodes.LoginFailure && Credentials != null)
{
autoProxyOptions.AutoLogonIfChallenged = true;
if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
if (!winHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
{
num = GetLastWin32Error();
num = getLastWin32Error();
}
}
}
......@@ -246,7 +246,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return num;
}
private bool WinHttpGetProxyForUrl(string destination,
private bool winHttpGetProxyForUrl(string destination,
ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString)
{
proxyListString = null;
......@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return flag;
}
private static int GetLastWin32Error()
private static int getLastWin32Error()
{
int lastWin32Error = Marshal.GetLastWin32Error();
if (lastWin32Error == 8)
......@@ -282,7 +282,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return lastWin32Error;
}
private static bool IsRecoverableAutoProxyError(NativeMethods.WinHttp.ErrorCodes errorCode)
private static bool isRecoverableAutoProxyError(NativeMethods.WinHttp.ErrorCodes errorCode)
{
switch (errorCode)
{
......@@ -300,7 +300,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
}
}
private static AutoWebProxyState GetStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode)
private static AutoWebProxyState getStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode)
{
if (errorCode == 0L)
{
......@@ -324,7 +324,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
}
}
private static string RemoveWhitespaces(string value)
private static string removeWhitespaces(string value)
{
var stringBuilder = new StringBuilder();
foreach (char c in value)
......@@ -338,7 +338,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return stringBuilder.ToString();
}
private static bool IsErrorFatalForAutoDetect(NativeMethods.WinHttp.ErrorCodes errorCode)
private static bool isErrorFatalForAutoDetect(NativeMethods.WinHttp.ErrorCodes errorCode)
{
switch (errorCode)
{
......
......@@ -24,7 +24,7 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// <param name="buffer"></param>
/// <param name="size"></param>
private static void ResizeBuffer(ref byte[] buffer, long size)
private static void resizeBuffer(ref byte[] buffer, long size)
{
var newBuffer = new byte[size];
Buffer.BlockCopy(buffer, 0, newBuffer, 0, buffer.Length);
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp;
......@@ -15,12 +16,9 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public class HttpWebClient
{
private readonly int bufferSize;
internal HttpWebClient(int bufferSize, Request request = null, Response response = null)
internal HttpWebClient(Request request = null, Response response = null)
{
this.bufferSize = bufferSize;
Request = request ?? new Request();
Response = response ?? new Response();
}
......@@ -30,6 +28,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
internal TcpServerConnection ServerConnection { get; set; }
/// <summary>
/// Should we close the server connection at the end of this HTTP request/response session.
/// </summary>
internal bool CloseServerConnection { get; set; }
/// <summary>
/// Stores internal data for the session.
/// </summary>
......@@ -99,15 +102,15 @@ namespace Titanium.Web.Proxy.Http
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
Request.HttpVersion), cancellationToken);
var headerBuilder = new StringBuilder();
// Send Authentication to Upstream proxy if needed
if (!isTransparent && upstreamProxy != null
&& ServerConnection.IsHttps == false
&& !string.IsNullOrEmpty(upstreamProxy.UserName)
&& upstreamProxy.Password != null)
{
await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer, cancellationToken);
await HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)
.WriteToStreamAsync(writer, cancellationToken);
headerBuilder.AppendLine(HttpHeader.ProxyConnectionKeepAlive.ToString());
headerBuilder.AppendLine(HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password).ToString());
}
// write request headers
......@@ -115,17 +118,30 @@ namespace Titanium.Web.Proxy.Http
{
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
{
await header.WriteToStreamAsync(writer, cancellationToken);
headerBuilder.AppendLine(header.ToString());
}
}
await writer.WriteLineAsync(cancellationToken);
headerBuilder.AppendLine();
await writer.WriteAsync(headerBuilder.ToString(), cancellationToken);
if (enable100ContinueBehaviour)
{
if (Request.ExpectContinue)
{
string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
string httpStatus;
try
{
httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null)
{
throw new ServerConnectionException("Server connection was closed.");
}
}
catch (Exception e) when (!(e is ServerConnectionException))
{
throw new ServerConnectionException("Server connection was closed.");
}
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription);
......@@ -159,10 +175,18 @@ namespace Titanium.Web.Proxy.Http
return;
}
string httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
string httpStatus;
try
{
httpStatus = await ServerConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null)
{
throw new IOException();
throw new ServerConnectionException("Server connection was closed.");
}
}
catch (Exception e) when (!(e is ServerConnectionException))
{
throw new ServerConnectionException("Server connection was closed.");
}
if (httpStatus == string.Empty)
......@@ -217,6 +241,9 @@ namespace Titanium.Web.Proxy.Http
ConnectRequest?.FinishSession();
Request?.FinishSession();
Response?.FinishSession();
Data.Clear();
UserData = null;
}
}
}
......@@ -99,7 +99,8 @@ namespace Titanium.Web.Proxy.Http
public string Url => RequestUri.OriginalString;
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request.
/// Cancels the client HTTP request without sending to server.
/// This should be set when API user responds with custom response.
/// </summary>
internal bool CancelRequest { get; set; }
......@@ -199,7 +200,7 @@ namespace Titanium.Web.Proxy.Http
// Find the request Verb
httpMethod = httpCmdSplit[0];
if (!IsAllUpper(httpMethod))
if (!isAllUpper(httpMethod))
{
httpMethod = httpMethod.ToUpper();
}
......@@ -219,7 +220,7 @@ namespace Titanium.Web.Proxy.Http
}
}
private static bool IsAllUpper(string input)
private static bool isAllUpper(string input)
{
for (int i = 0; i < input.Length; i++)
{
......@@ -232,5 +233,6 @@ namespace Titanium.Web.Proxy.Http
return true;
}
}
}
......@@ -23,10 +23,35 @@ namespace Titanium.Web.Proxy.Http
private string bodyString;
/// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters
/// Store whether the original request/response has body or not, since the user may change the parameters.
/// We need this detail to syphon out attached tcp connection for reuse.
/// </summary>
internal bool OriginalHasBody { get; set; }
/// <summary>
/// Store original content-length, since the user setting the body may change the parameters.
/// We need this detail to tcp syphon out attached connection for reuse.
/// </summary>
internal long OriginalContentLength { get; set; }
/// <summary>
/// Store whether the original request/response was a chunked body, since the user may change the parameters.
/// We need this detail to syphon out attached tcp connection for reuse.
/// </summary>
internal bool OriginalIsChunked { get; set; }
/// <summary>
/// Store whether the original request/response content-encoding, since the user may change the parameters.
/// We need this detail to syphon out attached tcp connection for reuse.
/// </summary>
internal string OriginalContentEncoding { get; set; }
/// <summary>
/// Store whether the original request/response body was read by user.
/// We need this detail to syphon out attached tcp connection for reuse.
/// </summary>
public bool OriginalIsBodyRead { get; internal set; }
/// <summary>
/// Keeps the body data after the session is finished.
/// </summary>
......@@ -168,6 +193,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// Also if user set this as a custom response then this should be true.
/// </summary>
internal bool Locked { get; set; }
......@@ -231,6 +257,31 @@ namespace Titanium.Web.Proxy.Http
ContentLength = IsChunked ? -1 : BodyInternal?.Length ?? 0;
}
/// <summary>
/// Set values for original headers using current headers.
/// </summary>
internal void SetOriginalHeaders()
{
OriginalHasBody = HasBody;
OriginalContentLength = ContentLength;
OriginalIsChunked = IsChunked;
OriginalContentEncoding = ContentEncoding;
OriginalIsBodyRead = IsBodyRead;
}
/// <summary>
/// Copy original header values.
/// </summary>
/// <param name="requestResponseBase"></param>
internal void SetOriginalHeaders(RequestResponseBase requestResponseBase)
{
OriginalHasBody = requestResponseBase.OriginalHasBody;
OriginalContentLength = requestResponseBase.OriginalContentLength;
OriginalIsChunked = requestResponseBase.OriginalIsChunked;
OriginalContentEncoding = requestResponseBase.OriginalContentEncoding;
OriginalIsBodyRead = requestResponseBase.OriginalIsBodyRead;
}
/// <summary>
/// Finish the session
/// </summary>
......
......@@ -92,8 +92,6 @@ namespace Titanium.Web.Proxy.Http
}
}
internal bool TerminateResponse { get; set; }
/// <summary>
/// Is response 100-continue
/// </summary>
......
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
using System.Text;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class Decoder
{
private readonly DynamicTable dynamicTable;
private readonly int maxHeaderSize;
private int maxDynamicTableSize;
private int encoderMaxDynamicTableSize;
private bool maxDynamicTableSizeChangeRequired;
private long headerSize;
private State state;
private HpackUtil.IndexType indexType;
private int index;
private bool huffmanEncoded;
private int skipLength;
private int nameLength;
private int valueLength;
private string name;
private enum State
{
ReadHeaderRepresentation,
ReadMaxDynamicTableSize,
ReadIndexedHeader,
ReadIndexedHeaderName,
ReadLiteralHeaderNameLengthPrefix,
ReadLiteralHeaderNameLength,
ReadLiteralHeaderName,
SkipLiteralHeaderName,
ReadLiteralHeaderValueLengthPrefix,
ReadLiteralHeaderValueLength,
ReadLiteralHeaderValue,
SkipLiteralHeaderValue
}
/// <summary>
/// Initializes a new instance of the <see cref="Decoder"/> class.
/// </summary>
/// <param name="maxHeaderSize">Max header size.</param>
/// <param name="maxHeaderTableSize">Max header table size.</param>
public Decoder(int maxHeaderSize, int maxHeaderTableSize)
{
dynamicTable = new DynamicTable(maxHeaderTableSize);
this.maxHeaderSize = maxHeaderSize;
maxDynamicTableSize = maxHeaderTableSize;
encoderMaxDynamicTableSize = maxHeaderTableSize;
maxDynamicTableSizeChangeRequired = false;
Reset();
}
private void Reset()
{
headerSize = 0;
state = State.ReadHeaderRepresentation;
indexType = HpackUtil.IndexType.None;
}
/// <summary>
/// Decode the header block into header fields.
/// </summary>
/// <param name="input">Input.</param>
/// <param name="headerListener">Header listener.</param>
public void Decode(BinaryReader input, IHeaderListener headerListener)
{
while (input.BaseStream.Length - input.BaseStream.Position > 0)
{
switch (state)
{
case State.ReadHeaderRepresentation:
sbyte b = input.ReadSByte();
if (maxDynamicTableSizeChangeRequired && (b & 0xE0) != 0x20)
{
// Encoder MUST signal maximum dynamic table size change
throw new IOException("max dynamic table size change required");
}
if (b < 0)
{
// Indexed Header Field
index = b & 0x7F;
if (index == 0)
{
throw new IOException("illegal index value (" + index + ")");
}
else if (index == 0x7F)
{
state = State.ReadIndexedHeader;
}
else
{
IndexHeader(index, headerListener);
}
}
else if ((b & 0x40) == 0x40)
{
// Literal Header Field with Incremental Indexing
indexType = HpackUtil.IndexType.Incremental;
index = b & 0x3F;
if (index == 0)
{
state = State.ReadLiteralHeaderNameLengthPrefix;
}
else if (index == 0x3F)
{
state = State.ReadIndexedHeaderName;
}
else
{
// Index was stored as the prefix
ReadName(index);
state = State.ReadLiteralHeaderValueLengthPrefix;
}
}
else if ((b & 0x20) == 0x20)
{
// Dynamic Table Size Update
index = b & 0x1F;
if (index == 0x1F)
{
state = State.ReadMaxDynamicTableSize;
}
else
{
SetDynamicTableSize(index);
state = State.ReadHeaderRepresentation;
}
}
else
{
// Literal Header Field without Indexing / never Indexed
indexType = ((b & 0x10) == 0x10) ? HpackUtil.IndexType.Never : HpackUtil.IndexType.None;
index = b & 0x0F;
if (index == 0)
{
state = State.ReadLiteralHeaderNameLengthPrefix;
}
else if (index == 0x0F)
{
state = State.ReadIndexedHeaderName;
}
else
{
// Index was stored as the prefix
ReadName(index);
state = State.ReadLiteralHeaderValueLengthPrefix;
}
}
break;
case State.ReadMaxDynamicTableSize:
int maxSize = decodeULE128(input);
if (maxSize == -1)
{
return;
}
// Check for numerical overflow
if (maxSize > int.MaxValue - index)
{
throw new IOException("decompression failure");
}
SetDynamicTableSize(index + maxSize);
state = State.ReadHeaderRepresentation;
break;
case State.ReadIndexedHeader:
int headerIndex = decodeULE128(input);
if (headerIndex == -1)
{
return;
}
// Check for numerical overflow
if (headerIndex > int.MaxValue - index)
{
throw new IOException("decompression failure");
}
IndexHeader(index + headerIndex, headerListener);
state = State.ReadHeaderRepresentation;
break;
case State.ReadIndexedHeaderName:
// Header Name matches an entry in the Header Table
int nameIndex = decodeULE128(input);
if (nameIndex == -1)
{
return;
}
// Check for numerical overflow
if (nameIndex > int.MaxValue - index)
{
throw new IOException("decompression failure");
}
ReadName(index + nameIndex);
state = State.ReadLiteralHeaderValueLengthPrefix;
break;
case State.ReadLiteralHeaderNameLengthPrefix:
b = input.ReadSByte();
huffmanEncoded = (b & 0x80) == 0x80;
index = b & 0x7F;
if (index == 0x7f)
{
state = State.ReadLiteralHeaderNameLength;
}
else
{
nameLength = index;
// Disallow empty names -- they cannot be represented in HTTP/1.x
if (nameLength == 0)
{
throw new IOException("decompression failure");
}
// Check name length against max header size
if (ExceedsMaxHeaderSize(nameLength))
{
if (indexType == HpackUtil.IndexType.None)
{
// Name is unused so skip bytes
name = string.Empty;
skipLength = nameLength;
state = State.SkipLiteralHeaderName;
break;
}
// Check name length against max dynamic table size
if (nameLength + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
{
dynamicTable.Clear();
name = string.Empty;
skipLength = nameLength;
state = State.SkipLiteralHeaderName;
break;
}
}
state = State.ReadLiteralHeaderName;
}
break;
case State.ReadLiteralHeaderNameLength:
// Header Name is a Literal String
nameLength = decodeULE128(input);
if (nameLength == -1)
{
return;
}
// Check for numerical overflow
if (nameLength > int.MaxValue - index)
{
throw new IOException("decompression failure");
}
nameLength += index;
// Check name length against max header size
if (ExceedsMaxHeaderSize(nameLength))
{
if (indexType == HpackUtil.IndexType.None)
{
// Name is unused so skip bytes
name = string.Empty;
skipLength = nameLength;
state = State.SkipLiteralHeaderName;
break;
}
// Check name length against max dynamic table size
if (nameLength + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
{
dynamicTable.Clear();
name = string.Empty;
skipLength = nameLength;
state = State.SkipLiteralHeaderName;
break;
}
}
state = State.ReadLiteralHeaderName;
break;
case State.ReadLiteralHeaderName:
// Wait until entire name is readable
if (input.BaseStream.Length - input.BaseStream.Position < nameLength)
{
return;
}
name = ReadStringLiteral(input, nameLength);
state = State.ReadLiteralHeaderValueLengthPrefix;
break;
case State.SkipLiteralHeaderName:
skipLength -= (int)input.BaseStream.Seek(skipLength, SeekOrigin.Current);
if (skipLength < 0)
{
skipLength = 0;
}
if (skipLength == 0)
{
state = State.ReadLiteralHeaderValueLengthPrefix;
}
break;
case State.ReadLiteralHeaderValueLengthPrefix:
b = input.ReadSByte();
huffmanEncoded = (b & 0x80) == 0x80;
index = b & 0x7F;
if (index == 0x7f)
{
state = State.ReadLiteralHeaderValueLength;
}
else
{
valueLength = index;
// Check new header size against max header size
long newHeaderSize1 = (long)nameLength + valueLength;
if (ExceedsMaxHeaderSize(newHeaderSize1))
{
// truncation will be reported during endHeaderBlock
headerSize = maxHeaderSize + 1;
if (indexType == HpackUtil.IndexType.None)
{
// Value is unused so skip bytes
state = State.SkipLiteralHeaderValue;
break;
}
// Check new header size against max dynamic table size
if (newHeaderSize1 + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
{
dynamicTable.Clear();
state = State.SkipLiteralHeaderValue;
break;
}
}
if (valueLength == 0)
{
InsertHeader(headerListener, name, string.Empty, indexType);
state = State.ReadHeaderRepresentation;
}
else
{
state = State.ReadLiteralHeaderValue;
}
}
break;
case State.ReadLiteralHeaderValueLength:
// Header Value is a Literal String
valueLength = decodeULE128(input);
if (valueLength == -1)
{
return;
}
// Check for numerical overflow
if (valueLength > int.MaxValue - index)
{
throw new IOException("decompression failure");
}
valueLength += index;
// Check new header size against max header size
long newHeaderSize2 = (long)nameLength + valueLength;
if (newHeaderSize2 + headerSize > maxHeaderSize)
{
// truncation will be reported during endHeaderBlock
headerSize = maxHeaderSize + 1;
if (indexType == HpackUtil.IndexType.None)
{
// Value is unused so skip bytes
state = State.SkipLiteralHeaderValue;
break;
}
// Check new header size against max dynamic table size
if (newHeaderSize2 + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
{
dynamicTable.Clear();
state = State.SkipLiteralHeaderValue;
break;
}
}
state = State.ReadLiteralHeaderValue;
break;
case State.ReadLiteralHeaderValue:
// Wait until entire value is readable
if (input.BaseStream.Length - input.BaseStream.Position < valueLength)
{
return;
}
var value = ReadStringLiteral(input, valueLength);
InsertHeader(headerListener, name, value, indexType);
state = State.ReadHeaderRepresentation;
break;
case State.SkipLiteralHeaderValue:
valueLength -= (int)input.BaseStream.Seek(valueLength, SeekOrigin.Current);
if (valueLength < 0)
{
valueLength = 0;
}
if (valueLength == 0)
{
state = State.ReadHeaderRepresentation;
}
break;
default:
throw new Exception("should not reach here");
}
}
}
/// <summary>
/// End the current header block. Returns if the header field has been truncated.
/// This must be called after the header block has been completely decoded.
/// </summary>
/// <returns><c>true</c>, if header block was ended, <c>false</c> otherwise.</returns>
public bool EndHeaderBlock()
{
bool truncated = headerSize > maxHeaderSize;
Reset();
return truncated;
}
/// <summary>
/// Set the maximum table size.
/// If this is below the maximum size of the dynamic table used by the encoder,
/// the beginning of the next header block MUST signal this change.
/// </summary>
/// <param name="maxHeaderTableSize">Max header table size.</param>
public void SetMaxHeaderTableSize(int maxHeaderTableSize)
{
maxDynamicTableSize = maxHeaderTableSize;
if (maxDynamicTableSize < encoderMaxDynamicTableSize)
{
// decoder requires less space than encoder
// encoder MUST signal this change
maxDynamicTableSizeChangeRequired = true;
dynamicTable.SetCapacity(maxDynamicTableSize);
}
}
/// <summary>
/// Return the maximum table size.
/// This is the maximum size allowed by both the encoder and the decoder.
/// </summary>
/// <returns>The max header table size.</returns>
public int GetMaxHeaderTableSize()
{
return dynamicTable.Capacity;
}
private void SetDynamicTableSize(int dynamicTableSize)
{
if (dynamicTableSize > maxDynamicTableSize)
{
throw new IOException("invalid max dynamic table size");
}
encoderMaxDynamicTableSize = dynamicTableSize;
maxDynamicTableSizeChangeRequired = false;
dynamicTable.SetCapacity(dynamicTableSize);
}
private HttpHeader GetHeaderField(int index)
{
if (index <= StaticTable.Length)
{
var headerField = StaticTable.Get(index);
return headerField;
}
else if (index - StaticTable.Length <= dynamicTable.Length())
{
var headerField = dynamicTable.GetEntry(index - StaticTable.Length);
return headerField;
}
else
{
throw new IOException("illegal index value (" + index + ")");
}
}
private void ReadName(int index)
{
name = GetHeaderField(index).Name;
}
private void IndexHeader(int index, IHeaderListener headerListener)
{
var headerField = GetHeaderField(index);
AddHeader(headerListener, headerField.Name, headerField.Value, false);
}
private void InsertHeader(IHeaderListener headerListener, string name, string value, HpackUtil.IndexType indexType)
{
AddHeader(headerListener, name, value, indexType == HpackUtil.IndexType.Never);
switch (indexType)
{
case HpackUtil.IndexType.None:
case HpackUtil.IndexType.Never:
break;
case HpackUtil.IndexType.Incremental:
dynamicTable.Add(new HttpHeader(name, value));
break;
default:
throw new Exception("should not reach here");
}
}
private void AddHeader(IHeaderListener headerListener, string name, string value, bool sensitive)
{
if (name.Length == 0)
{
throw new ArgumentException("name is empty");
}
long newSize = headerSize + name.Length + value.Length;
if (newSize <= maxHeaderSize)
{
headerListener.AddHeader(name, value, sensitive);
headerSize = (int)newSize;
}
else
{
// truncation will be reported during endHeaderBlock
headerSize = maxHeaderSize + 1;
}
}
private bool ExceedsMaxHeaderSize(long size)
{
// Check new header size against max header size
if (size + headerSize <= maxHeaderSize)
{
return false;
}
// truncation will be reported during endHeaderBlock
headerSize = maxHeaderSize + 1;
return true;
}
private string ReadStringLiteral(BinaryReader input, int length)
{
var buf = new byte[length];
int lengthToRead = length;
if (input.BaseStream.Length - input.BaseStream.Position < length)
{
lengthToRead = (int)input.BaseStream.Length - (int)input.BaseStream.Position;
}
int readBytes = input.Read(buf, 0, lengthToRead);
if (readBytes != length)
{
throw new IOException("decompression failure");
}
return huffmanEncoded ? HuffmanDecoder.Instance.Decode(buf) : Encoding.UTF8.GetString(buf);
}
// Unsigned Little Endian Base 128 Variable-Length Integer Encoding
private static int decodeULE128(BinaryReader input)
{
long markedPosition = input.BaseStream.Position;
int result = 0;
int shift = 0;
while (shift < 32)
{
if (input.BaseStream.Length - input.BaseStream.Position == 0)
{
// Buffer does not contain entire integer,
// reset reader index and return -1.
input.BaseStream.Position = markedPosition;
return -1;
}
sbyte b = input.ReadSByte();
if (shift == 28 && (b & 0xF8) != 0)
{
break;
}
result |= (b & 0x7F) << shift;
if ((b & 0x80) == 0)
{
return result;
}
shift += 7;
}
// Value exceeds Integer.MAX_VALUE
input.BaseStream.Position = markedPosition;
throw new IOException("decompression failure");
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class DynamicTable
{
// a circular queue of header fields
HttpHeader[] headerFields;
int head;
int tail;
/// <summary>
/// Return the maximum allowable size of the dynamic table.
/// </summary>
/// <value>
/// The capacity.
/// </value>
// ensure setCapacity creates the array
public int Capacity { get; private set; } = -1;
/// <summary>
/// Return the current size of the dynamic table.
/// This is the sum of the size of the entries.
/// </summary>
/// <value>
/// The size.
/// </value>
public int Size { get; private set; }
/// <summary>
/// Creates a new dynamic table with the specified initial capacity.
/// </summary>
/// <param name="initialCapacity">Initial capacity.</param>
public DynamicTable(int initialCapacity)
{
SetCapacity(initialCapacity);
}
/// <summary>
/// Return the number of header fields in the dynamic table.
/// </summary>
public int Length()
{
int length;
if (head < tail)
{
length = headerFields.Length - tail + head;
}
else
{
length = head - tail;
}
return length;
}
/// <summary>
/// Return the header field at the given index.
/// The first and newest entry is always at index 1,
/// and the oldest entry is at the index length().
/// </summary>
/// <returns>The entry.</returns>
/// <param name="index">Index.</param>
public HttpHeader GetEntry(int index)
{
if (index <= 0 || index > Length())
{
throw new IndexOutOfRangeException();
}
int i = head - index;
if (i < 0)
{
return headerFields[i + headerFields.Length];
}
return headerFields[i];
}
/// <summary>
/// Add the header field to the dynamic table.
/// Entries are evicted from the dynamic table until the size of the table
/// and the new header field is less than or equal to the table's capacity.
/// If the size of the new entry is larger than the table's capacity,
/// the dynamic table will be cleared.
/// </summary>
/// <param name="header">Header.</param>
public void Add(HttpHeader header)
{
int headerSize = header.Size;
if (headerSize > Capacity)
{
Clear();
return;
}
while (Size + headerSize > Capacity)
{
Remove();
}
headerFields[head++] = header;
Size += header.Size;
if (head == headerFields.Length)
{
head = 0;
}
}
/// <summary>
/// Remove and return the oldest header field from the dynamic table.
/// </summary>
public HttpHeader Remove()
{
var removed = headerFields[tail];
if (removed == null)
{
return null;
}
Size -= removed.Size;
headerFields[tail++] = null;
if (tail == headerFields.Length)
{
tail = 0;
}
return removed;
}
/// <summary>
/// Remove all entries from the dynamic table.
/// </summary>
public void Clear()
{
while (tail != head)
{
headerFields[tail++] = null;
if (tail == headerFields.Length)
{
tail = 0;
}
}
head = 0;
tail = 0;
Size = 0;
}
/// <summary>
/// Set the maximum size of the dynamic table.
/// Entries are evicted from the dynamic table until the size of the table
/// is less than or equal to the maximum size.
/// </summary>
/// <param name="capacity">Capacity.</param>
public void SetCapacity(int capacity)
{
if (capacity < 0)
{
throw new ArgumentException("Illegal Capacity: " + capacity);
}
// initially capacity will be -1 so init won't return here
if (Capacity == capacity)
{
return;
}
Capacity = capacity;
if (capacity == 0)
{
Clear();
}
else
{
// initially size will be 0 so remove won't be called
while (Size > capacity)
{
Remove();
}
}
int maxEntries = capacity / HttpHeader.HttpHeaderOverhead;
if (capacity % HttpHeader.HttpHeaderOverhead != 0)
{
maxEntries++;
}
// check if capacity change requires us to reallocate the array
if (headerFields != null && headerFields.Length == maxEntries)
{
return;
}
var tmp = new HttpHeader[maxEntries];
// initially length will be 0 so there will be no copy
int len = Length();
int cursor = tail;
for (int i = 0; i < len; i++)
{
var entry = headerFields[cursor++];
tmp[i] = entry;
if (cursor == headerFields.Length)
{
cursor = 0;
}
}
tail = 0;
head = tail + len;
headerFields = tmp;
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
using System.Text;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class Encoder
{
private const int bucketSize = 17;
// a linked hash map of header fields
private readonly HeaderEntry[] headerFields = new HeaderEntry[bucketSize];
private readonly HeaderEntry head = new HeaderEntry(-1, string.Empty, string.Empty, int.MaxValue, null);
private int size;
/// <summary>
/// Gets the the maximum table size.
/// </summary>
/// <value>
/// The max header table size.
/// </value>
public int MaxHeaderTableSize { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="Encoder"/> class.
/// </summary>
/// <param name="maxHeaderTableSize">Max header table size.</param>
public Encoder(int maxHeaderTableSize)
{
if (maxHeaderTableSize < 0)
{
throw new ArgumentException("Illegal Capacity: " + maxHeaderTableSize);
}
MaxHeaderTableSize = maxHeaderTableSize;
head.Before = head.After = head;
}
/// <summary>
/// Encode the header field into the header block.
/// </summary>
/// <param name="output">Output.</param>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="sensitive">If set to <c>true</c> sensitive.</param>
public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false)
{
// If the header value is sensitive then it must never be indexed
if (sensitive)
{
int nameIndex = getNameIndex(name);
encodeLiteral(output, name, value, HpackUtil.IndexType.Never, nameIndex);
return;
}
// If the peer will only use the static table
if (MaxHeaderTableSize == 0)
{
int staticTableIndex = StaticTable.GetIndex(name, value);
if (staticTableIndex == -1)
{
int nameIndex = StaticTable.GetIndex(name);
encodeLiteral(output, name, value, HpackUtil.IndexType.None, nameIndex);
}
else
{
encodeInteger(output, 0x80, 7, staticTableIndex);
}
return;
}
int headerSize = HttpHeader.SizeOf(name, value);
// If the headerSize is greater than the max table size then it must be encoded literally
if (headerSize > MaxHeaderTableSize)
{
int nameIndex = getNameIndex(name);
encodeLiteral(output, name, value, HpackUtil.IndexType.None, nameIndex);
return;
}
var headerField = getEntry(name, value);
if (headerField != null)
{
int index = getIndex(headerField.Index) + StaticTable.Length;
// Section 6.1. Indexed Header Field Representation
encodeInteger(output, 0x80, 7, index);
}
else
{
int staticTableIndex = StaticTable.GetIndex(name, value);
if (staticTableIndex != -1)
{
// Section 6.1. Indexed Header Field Representation
encodeInteger(output, 0x80, 7, staticTableIndex);
}
else
{
int nameIndex = getNameIndex(name);
ensureCapacity(headerSize);
var indexType = HpackUtil.IndexType.Incremental;
encodeLiteral(output, name, value, indexType, nameIndex);
add(name, value);
}
}
}
/// <summary>
/// Set the maximum table size.
/// </summary>
/// <param name="output">Output.</param>
/// <param name="maxHeaderTableSize">Max header table size.</param>
public void SetMaxHeaderTableSize(BinaryWriter output, int maxHeaderTableSize)
{
if (maxHeaderTableSize < 0)
{
throw new ArgumentException("Illegal Capacity", nameof(maxHeaderTableSize));
}
if (MaxHeaderTableSize == maxHeaderTableSize)
{
return;
}
MaxHeaderTableSize = maxHeaderTableSize;
ensureCapacity(0);
encodeInteger(output, 0x20, 5, maxHeaderTableSize);
}
/// <summary>
/// Encode integer according to Section 5.1.
/// </summary>
/// <param name="output">Output.</param>
/// <param name="mask">Mask.</param>
/// <param name="n">N.</param>
/// <param name="i">The index.</param>
private static void encodeInteger(BinaryWriter output, int mask, int n, int i)
{
if (n < 0 || n > 8)
{
throw new ArgumentException("N: " + n);
}
int nbits = 0xFF >> (8 - n);
if (i < nbits)
{
output.Write((byte)(mask | i));
}
else
{
output.Write((byte)(mask | nbits));
int length = i - nbits;
while (true)
{
if ((length & ~0x7F) == 0)
{
output.Write((byte)length);
return;
}
output.Write((byte)((length & 0x7F) | 0x80));
length >>= 7;
}
}
}
/// <summary>
/// Encode string literal according to Section 5.2.
/// </summary>
/// <param name="output">Output.</param>
/// <param name="stringLiteral">String literal.</param>
private void encodeStringLiteral(BinaryWriter output, string stringLiteral)
{
var stringData = Encoding.UTF8.GetBytes(stringLiteral);
int huffmanLength = HuffmanEncoder.Instance.GetEncodedLength(stringData);
if (huffmanLength < stringLiteral.Length)
{
encodeInteger(output, 0x80, 7, huffmanLength);
HuffmanEncoder.Instance.Encode(output, stringData);
}
else
{
encodeInteger(output, 0x00, 7, stringData.Length);
output.Write(stringData, 0, stringData.Length);
}
}
/// <summary>
/// Encode literal header field according to Section 6.2.
/// </summary>
/// <param name="output">Output.</param>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="indexType">Index type.</param>
/// <param name="nameIndex">Name index.</param>
private void encodeLiteral(BinaryWriter output, string name, string value, HpackUtil.IndexType indexType,
int nameIndex)
{
int mask;
int prefixBits;
switch (indexType)
{
case HpackUtil.IndexType.Incremental:
mask = 0x40;
prefixBits = 6;
break;
case HpackUtil.IndexType.None:
mask = 0x00;
prefixBits = 4;
break;
case HpackUtil.IndexType.Never:
mask = 0x10;
prefixBits = 4;
break;
default:
throw new Exception("should not reach here");
}
encodeInteger(output, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex);
if (nameIndex == -1)
{
encodeStringLiteral(output, name);
}
encodeStringLiteral(output, value);
}
private int getNameIndex(string name)
{
int index = StaticTable.GetIndex(name);
if (index == -1)
{
index = getIndex(name);
if (index >= 0)
{
index += StaticTable.Length;
}
}
return index;
}
/// <summary>
/// Ensure that the dynamic table has enough room to hold 'headerSize' more bytes.
/// Removes the oldest entry from the dynamic table until sufficient space is available.
/// </summary>
/// <param name="headerSize">Header size.</param>
private void ensureCapacity(int headerSize)
{
while (size + headerSize > MaxHeaderTableSize)
{
int index = length();
if (index == 0)
{
break;
}
remove();
}
}
/// <summary>
/// Return the number of header fields in the dynamic table.
/// </summary>
private int length()
{
return size == 0 ? 0 : head.After.Index - head.Before.Index + 1;
}
/// <summary>
/// Returns the header entry with the lowest index value for the header field.
/// Returns null if header field is not in the dynamic table.
/// </summary>
/// <returns>The entry.</returns>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
private HeaderEntry getEntry(string name, string value)
{
if (length() == 0 || name == null || value == null)
{
return null;
}
int h = hash(name);
int i = index(h);
for (var e = headerFields[i]; e != null; e = e.Next)
{
if (e.Hash == h && Equals(name, e.Name) && Equals(value, e.Value))
{
return e;
}
}
return null;
}
/// <summary>
/// Returns the lowest index value for the header field name in the dynamic table.
/// Returns -1 if the header field name is not in the dynamic table.
/// </summary>
/// <returns>The index.</returns>
/// <param name="name">Name.</param>
private int getIndex(string name)
{
if (length() == 0 || name == null)
{
return -1;
}
int h = hash(name);
int i = Encoder.index(h);
int index = -1;
for (var e = headerFields[i]; e != null; e = e.Next)
{
if (e.Hash == h && HpackUtil.Equals(name, e.Name))
{
index = e.Index;
break;
}
}
return getIndex(index);
}
/// <summary>
/// Compute the index into the dynamic table given the index in the header entry.
/// </summary>
/// <returns>The index.</returns>
/// <param name="index">Index.</param>
private int getIndex(int index)
{
if (index == -1)
{
return index;
}
return index - head.Before.Index + 1;
}
/// <summary>
/// Add the header field to the dynamic table.
/// Entries are evicted from the dynamic table until the size of the table
/// and the new header field is less than the table's capacity.
/// If the size of the new entry is larger than the table's capacity,
/// the dynamic table will be cleared.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
private void add(string name, string value)
{
int headerSize = HttpHeader.SizeOf(name, value);
// Clear the table if the header field size is larger than the capacity.
if (headerSize > MaxHeaderTableSize)
{
clear();
return;
}
// Evict oldest entries until we have enough capacity.
while (size + headerSize > MaxHeaderTableSize)
{
remove();
}
int h = hash(name);
int i = index(h);
var old = headerFields[i];
var e = new HeaderEntry(h, name, value, head.Before.Index - 1, old);
headerFields[i] = e;
e.AddBefore(head);
size += headerSize;
}
/// <summary>
/// Remove and return the oldest header field from the dynamic table.
/// </summary>
private HttpHeader remove()
{
if (size == 0)
{
return null;
}
var eldest = head.After;
int h = eldest.Hash;
int i = index(h);
var prev = headerFields[i];
var e = prev;
while (e != null)
{
var next = e.Next;
if (e == eldest)
{
if (prev == eldest)
{
headerFields[i] = next;
}
else
{
prev.Next = next;
}
eldest.Remove();
size -= eldest.Size;
return eldest;
}
prev = e;
e = next;
}
return null;
}
/// <summary>
/// Remove all entries from the dynamic table.
/// </summary>
private void clear()
{
for (int i = 0; i < headerFields.Length; i++)
{
headerFields[i] = null;
}
head.Before = head.After = head;
size = 0;
}
/// <summary>
/// Returns the hash code for the given header field name.
/// </summary>
/// <returns><c>true</c> if hash name; otherwise, <c>false</c>.</returns>
/// <param name="name">Name.</param>
private static int hash(string name)
{
int h = 0;
for (int i = 0; i < name.Length; i++)
{
h = 31 * h + name[i];
}
if (h > 0)
{
return h;
}
if (h == int.MinValue)
{
return int.MaxValue;
}
return -h;
}
/// <summary>
/// Returns the index into the hash table for the hash code h.
/// </summary>
/// <param name="h">The height.</param>
private static int index(int h)
{
return h % bucketSize;
}
/// <summary>
/// A linked hash map HeaderField entry.
/// </summary>
private class HeaderEntry : HttpHeader
{
// This is used to compute the index in the dynamic table.
// These properties comprise the doubly linked list used for iteration.
public HeaderEntry Before { get; set; }
public HeaderEntry After { get; set; }
// These fields comprise the chained list for header fields with the same hash.
public HeaderEntry Next { get; set; }
public int Hash { get; }
public int Index { get; }
/// <summary>
/// Creates new entry.
/// </summary>
/// <param name="hash">Hash.</param>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="index">Index.</param>
/// <param name="next">Next.</param>
public HeaderEntry(int hash, string name, string value, int index, HeaderEntry next) : base(name, value)
{
Index = index;
Hash = hash;
Next = next;
}
/// <summary>
/// Removes this entry from the linked list.
/// </summary>
public void Remove()
{
Before.After = After;
After.Before = Before;
}
/// <summary>
/// Inserts this entry before the specified existing entry in the list.
/// </summary>
/// <param name="existingEntry">Existing entry.</param>
public void AddBefore(HeaderEntry existingEntry)
{
After = existingEntry;
Before = existingEntry.Before;
Before.After = this;
After.Before = this;
}
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public static class HpackUtil
{
// Section 6.2. Literal Header Field Representation
public enum IndexType
{
Incremental, // Section 6.2.1. Literal Header Field with Incremental Indexing
None, // Section 6.2.2. Literal Header Field without Indexing
Never // Section 6.2.3. Literal Header Field never Indexed
}
// Appendix B: Huffman Codes
// http://tools.ietf.org/html/rfc7541#appendix-B
public static readonly int[] HuffmanCodes = {
0x1ff8,
0x7fffd8,
0xfffffe2,
0xfffffe3,
0xfffffe4,
0xfffffe5,
0xfffffe6,
0xfffffe7,
0xfffffe8,
0xffffea,
0x3ffffffc,
0xfffffe9,
0xfffffea,
0x3ffffffd,
0xfffffeb,
0xfffffec,
0xfffffed,
0xfffffee,
0xfffffef,
0xffffff0,
0xffffff1,
0xffffff2,
0x3ffffffe,
0xffffff3,
0xffffff4,
0xffffff5,
0xffffff6,
0xffffff7,
0xffffff8,
0xffffff9,
0xffffffa,
0xffffffb,
0x14,
0x3f8,
0x3f9,
0xffa,
0x1ff9,
0x15,
0xf8,
0x7fa,
0x3fa,
0x3fb,
0xf9,
0x7fb,
0xfa,
0x16,
0x17,
0x18,
0x0,
0x1,
0x2,
0x19,
0x1a,
0x1b,
0x1c,
0x1d,
0x1e,
0x1f,
0x5c,
0xfb,
0x7ffc,
0x20,
0xffb,
0x3fc,
0x1ffa,
0x21,
0x5d,
0x5e,
0x5f,
0x60,
0x61,
0x62,
0x63,
0x64,
0x65,
0x66,
0x67,
0x68,
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x6e,
0x6f,
0x70,
0x71,
0x72,
0xfc,
0x73,
0xfd,
0x1ffb,
0x7fff0,
0x1ffc,
0x3ffc,
0x22,
0x7ffd,
0x3,
0x23,
0x4,
0x24,
0x5,
0x25,
0x26,
0x27,
0x6,
0x74,
0x75,
0x28,
0x29,
0x2a,
0x7,
0x2b,
0x76,
0x2c,
0x8,
0x9,
0x2d,
0x77,
0x78,
0x79,
0x7a,
0x7b,
0x7ffe,
0x7fc,
0x3ffd,
0x1ffd,
0xffffffc,
0xfffe6,
0x3fffd2,
0xfffe7,
0xfffe8,
0x3fffd3,
0x3fffd4,
0x3fffd5,
0x7fffd9,
0x3fffd6,
0x7fffda,
0x7fffdb,
0x7fffdc,
0x7fffdd,
0x7fffde,
0xffffeb,
0x7fffdf,
0xffffec,
0xffffed,
0x3fffd7,
0x7fffe0,
0xffffee,
0x7fffe1,
0x7fffe2,
0x7fffe3,
0x7fffe4,
0x1fffdc,
0x3fffd8,
0x7fffe5,
0x3fffd9,
0x7fffe6,
0x7fffe7,
0xffffef,
0x3fffda,
0x1fffdd,
0xfffe9,
0x3fffdb,
0x3fffdc,
0x7fffe8,
0x7fffe9,
0x1fffde,
0x7fffea,
0x3fffdd,
0x3fffde,
0xfffff0,
0x1fffdf,
0x3fffdf,
0x7fffeb,
0x7fffec,
0x1fffe0,
0x1fffe1,
0x3fffe0,
0x1fffe2,
0x7fffed,
0x3fffe1,
0x7fffee,
0x7fffef,
0xfffea,
0x3fffe2,
0x3fffe3,
0x3fffe4,
0x7ffff0,
0x3fffe5,
0x3fffe6,
0x7ffff1,
0x3ffffe0,
0x3ffffe1,
0xfffeb,
0x7fff1,
0x3fffe7,
0x7ffff2,
0x3fffe8,
0x1ffffec,
0x3ffffe2,
0x3ffffe3,
0x3ffffe4,
0x7ffffde,
0x7ffffdf,
0x3ffffe5,
0xfffff1,
0x1ffffed,
0x7fff2,
0x1fffe3,
0x3ffffe6,
0x7ffffe0,
0x7ffffe1,
0x3ffffe7,
0x7ffffe2,
0xfffff2,
0x1fffe4,
0x1fffe5,
0x3ffffe8,
0x3ffffe9,
0xffffffd,
0x7ffffe3,
0x7ffffe4,
0x7ffffe5,
0xfffec,
0xfffff3,
0xfffed,
0x1fffe6,
0x3fffe9,
0x1fffe7,
0x1fffe8,
0x7ffff3,
0x3fffea,
0x3fffeb,
0x1ffffee,
0x1ffffef,
0xfffff4,
0xfffff5,
0x3ffffea,
0x7ffff4,
0x3ffffeb,
0x7ffffe6,
0x3ffffec,
0x3ffffed,
0x7ffffe7,
0x7ffffe8,
0x7ffffe9,
0x7ffffea,
0x7ffffeb,
0xffffffe,
0x7ffffec,
0x7ffffed,
0x7ffffee,
0x7ffffef,
0x7fffff0,
0x3ffffee,
0x3fffffff // EOS
};
public static readonly byte[] HuffmanCodeLengths = {
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
30 // EOS
};
public const int HuffmanEos = 256;
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
using System.Text;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class HuffmanDecoder
{
/// <summary>
/// Huffman Decoder
/// </summary>
public static readonly HuffmanDecoder Instance = new HuffmanDecoder();
private readonly Node root;
/// <summary>
/// Creates a new Huffman decoder with the specified Huffman coding.
/// </summary>
private HuffmanDecoder()
{
// the Huffman codes indexed by symbol
var codes = HpackUtil.HuffmanCodes;
// the length of each Huffman code
var lengths = HpackUtil.HuffmanCodeLengths;
if (codes.Length != 257 || codes.Length != lengths.Length)
{
throw new ArgumentException("invalid Huffman coding");
}
root = BuildTree(codes, lengths);
}
/// <summary>
/// Decompresses the given Huffman coded string literal.
/// </summary>
/// <param name="buf">the string literal to be decoded</param>
/// <returns>the output stream for the compressed data</returns>
/// <exception cref="IOException">throws IOException if an I/O error occurs. In particular, an <code>IOException</code> may be thrown if the output stream has been closed.</exception>
public string Decode(byte[] buf)
{
var resultBuf = new byte[buf.Length * 2];
int resultSize = 0;
var node = root;
int current = 0;
int bits = 0;
for (int i = 0; i < buf.Length; i++)
{
int b = buf[i];
current = (current << 8) | b;
bits += 8;
while (bits >= 8)
{
int c = (current >> (bits - 8)) & 0xFF;
node = node.Children[c];
bits -= node.Bits;
if (node.IsTerminal)
{
if (node.Symbol == HpackUtil.HuffmanEos)
{
throw new IOException("EOS Decoded");
}
resultBuf[resultSize++] = (byte)node.Symbol;
node = root;
}
}
}
while (bits > 0)
{
int c = (current << (8 - bits)) & 0xFF;
node = node.Children[c];
if (node.IsTerminal && node.Bits <= bits)
{
bits -= node.Bits;
resultBuf[resultSize++] = (byte)node.Symbol;
node = root;
}
else
{
break;
}
}
// Section 5.2. String Literal Representation
// Padding not corresponding to the most significant bits of the code
// for the EOS symbol (0xFF) MUST be treated as a decoding error.
int mask = (1 << bits) - 1;
if ((current & mask) != mask)
{
throw new IOException("Invalid Padding");
}
return Encoding.UTF8.GetString(resultBuf, 0, resultSize);
}
private class Node
{
// terminal nodes have a symbol
public int Symbol { get; }
// number of bits matched by the node
public int Bits { get; }
// internal nodes have children
public Node[] Children { get; }
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanDecoder"/> class.
/// </summary>
public Node()
{
Symbol = 0;
Bits = 8;
Children = new Node[256];
}
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanDecoder"/> class.
/// </summary>
/// <param name="symbol">the symbol the node represents</param>
/// <param name="bits">the number of bits matched by this node</param>
public Node(int symbol, int bits)
{
//assert(bits > 0 && bits <= 8);
Symbol = symbol;
Bits = bits;
Children = null;
}
public bool IsTerminal => Children == null;
}
private static Node BuildTree(int[] codes, byte[] lengths)
{
var root = new Node();
for (int i = 0; i < codes.Length; i++)
{
Insert(root, i, codes[i], lengths[i]);
}
return root;
}
private static void Insert(Node root, int symbol, int code, byte length)
{
// traverse tree using the most significant bytes of code
var current = root;
while (length > 8)
{
if (current.IsTerminal)
{
throw new InvalidDataException("invalid Huffman code: prefix not unique");
}
length -= 8;
int i = (code >> length) & 0xFF;
if (current.Children[i] == null)
{
current.Children[i] = new Node();
}
current = current.Children[i];
}
var terminal = new Node(symbol, length);
int shift = 8 - length;
int start = (code << shift) & 0xFF;
int end = 1 << shift;
for (int i = start; i < start + end; i++)
{
current.Children[i] = terminal;
}
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class HuffmanEncoder
{
/// <summary>
/// Huffman Encoder
/// </summary>
public static readonly HuffmanEncoder Instance = new HuffmanEncoder();
/// <summary>
/// the Huffman codes indexed by symbol
/// </summary>
private readonly int[] codes = HpackUtil.HuffmanCodes;
/// <summary>
/// the length of each Huffman code
/// </summary>
private readonly byte[] lengths = HpackUtil.HuffmanCodeLengths;
/// <summary>
/// Compresses the input string literal using the Huffman coding.
/// </summary>
/// <param name="output">the output stream for the compressed data</param>
/// <param name="data">the string literal to be Huffman encoded</param>
/// <exception cref="IOException">if an I/O error occurs.</exception>
/// <see cref="Encode(BinaryWriter,byte[],int,int)"/>
public void Encode(BinaryWriter output, byte[] data)
{
Encode(output, data, 0, data.Length);
}
/// <summary>
/// Compresses the input string literal using the Huffman coding.
/// </summary>
/// <param name="output">the output stream for the compressed data</param>
/// <param name="data">the string literal to be Huffman encoded</param>
/// <param name="off">the start offset in the data</param>
/// <param name="len">the number of bytes to encode</param>
/// <exception cref="IOException">if an I/O error occurs. In particular, an <code>IOException</code> may be thrown if the output stream has been closed.</exception>
public void Encode(BinaryWriter output, byte[] data, int off, int len)
{
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (off < 0 || len < 0 || (off + len) < 0 || off > data.Length || (off + len) > data.Length)
{
throw new IndexOutOfRangeException();
}
if (len == 0)
{
return;
}
long current = 0L;
int n = 0;
for (int i = 0; i < len; i++)
{
int b = data[off + i] & 0xFF;
uint code = (uint)codes[b];
int nbits = lengths[b];
current <<= nbits;
current |= code;
n += nbits;
while (n >= 8)
{
n -= 8;
output.Write(((byte)(current >> n)));
}
}
if (n > 0)
{
current <<= (8 - n);
current |= (uint)(0xFF >> n); // this should be EOS symbol
output.Write((byte)current);
}
}
/// <summary>
/// Returns the number of bytes required to Huffman encode the input string literal.
/// </summary>
/// <returns>the number of bytes required to Huffman encode <code>data</code></returns>
/// <param name="data">the string literal to be Huffman encoded</param>
public int GetEncodedLength(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
long len = 0L;
foreach (byte b in data)
{
len += lengths[b];
}
return (int)((len + 7) >> 3);
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Titanium.Web.Proxy.Http2.Hpack
{
public interface IHeaderListener
{
/// <summary>
/// EmitHeader is called by the decoder during header field emission.
/// The name and value byte arrays must not be modified.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="sensitive">If set to <c>true</c> sensitive.</param>
void AddHeader(string name, string value, bool sensitive);
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public static class StaticTable
{
/// <summary>
/// Appendix A: Static Table Definition
/// </summary>
/// <see cref="http://tools.ietf.org/html/rfc7541#appendix-A"/>
private static readonly List<HttpHeader> staticTable = new List<HttpHeader>()
{
/* 1 */
new HttpHeader(":authority", string.Empty),
/* 2 */
new HttpHeader(":method", "GET"),
/* 3 */
new HttpHeader(":method", "POST"),
/* 4 */
new HttpHeader(":path", "/"),
/* 5 */
new HttpHeader(":path", "/index.html"),
/* 6 */
new HttpHeader(":scheme", "http"),
/* 7 */
new HttpHeader(":scheme", "https"),
/* 8 */
new HttpHeader(":status", "200"),
/* 9 */
new HttpHeader(":status", "204"),
/* 10 */
new HttpHeader(":status", "206"),
/* 11 */
new HttpHeader(":status", "304"),
/* 12 */
new HttpHeader(":status", "400"),
/* 13 */
new HttpHeader(":status", "404"),
/* 14 */
new HttpHeader(":status", "500"),
/* 15 */
new HttpHeader("accept-charset", string.Empty),
/* 16 */
new HttpHeader("accept-encoding", "gzip, deflate"),
/* 17 */
new HttpHeader("accept-language", string.Empty),
/* 18 */
new HttpHeader("accept-ranges", string.Empty),
/* 19 */
new HttpHeader("accept", string.Empty),
/* 20 */
new HttpHeader("access-control-allow-origin", string.Empty),
/* 21 */
new HttpHeader("age", string.Empty),
/* 22 */
new HttpHeader("allow", string.Empty),
/* 23 */
new HttpHeader("authorization", string.Empty),
/* 24 */
new HttpHeader("cache-control", string.Empty),
/* 25 */
new HttpHeader("content-disposition", string.Empty),
/* 26 */
new HttpHeader("content-encoding", string.Empty),
/* 27 */
new HttpHeader("content-language", string.Empty),
/* 28 */
new HttpHeader("content-length", string.Empty),
/* 29 */
new HttpHeader("content-location", string.Empty),
/* 30 */
new HttpHeader("content-range", string.Empty),
/* 31 */
new HttpHeader("content-type", string.Empty),
/* 32 */
new HttpHeader("cookie", string.Empty),
/* 33 */
new HttpHeader("date", string.Empty),
/* 34 */
new HttpHeader("etag", string.Empty),
/* 35 */
new HttpHeader("expect", string.Empty),
/* 36 */
new HttpHeader("expires", string.Empty),
/* 37 */
new HttpHeader("from", string.Empty),
/* 38 */
new HttpHeader("host", string.Empty),
/* 39 */
new HttpHeader("if-match", string.Empty),
/* 40 */
new HttpHeader("if-modified-since", string.Empty),
/* 41 */
new HttpHeader("if-none-match", string.Empty),
/* 42 */
new HttpHeader("if-range", string.Empty),
/* 43 */
new HttpHeader("if-unmodified-since", string.Empty),
/* 44 */
new HttpHeader("last-modified", string.Empty),
/* 45 */
new HttpHeader("link", string.Empty),
/* 46 */
new HttpHeader("location", string.Empty),
/* 47 */
new HttpHeader("max-forwards", string.Empty),
/* 48 */
new HttpHeader("proxy-authenticate", string.Empty),
/* 49 */
new HttpHeader("proxy-authorization", string.Empty),
/* 50 */
new HttpHeader("range", string.Empty),
/* 51 */
new HttpHeader("referer", string.Empty),
/* 52 */
new HttpHeader("refresh", string.Empty),
/* 53 */
new HttpHeader("retry-after", string.Empty),
/* 54 */
new HttpHeader("server", string.Empty),
/* 55 */
new HttpHeader("set-cookie", string.Empty),
/* 56 */
new HttpHeader("strict-transport-security", string.Empty),
/* 57 */
new HttpHeader("transfer-encoding", string.Empty),
/* 58 */
new HttpHeader("user-agent", string.Empty),
/* 59 */
new HttpHeader("vary", string.Empty),
/* 60 */
new HttpHeader("via", string.Empty),
/* 61 */
new HttpHeader("www-authenticate", string.Empty)
};
private static readonly Dictionary<string, int> staticIndexByName = CreateMap();
/// <summary>
/// The number of header fields in the static table.
/// </summary>
/// <value>The length.</value>
public static int Length => staticTable.Count;
/// <summary>
/// Return the http header field at the given index value.
/// </summary>
/// <returns>The header field.</returns>
/// <param name="index">Index.</param>
public static HttpHeader Get(int index)
{
return staticTable[index - 1];
}
/// <summary>
/// Returns the lowest index value for the given header field name in the static table.
/// Returns -1 if the header field name is not in the static table.
/// </summary>
/// <returns>The index.</returns>
/// <param name="name">Name.</param>
public static int GetIndex(string name)
{
if (!staticIndexByName.ContainsKey(name))
{
return -1;
}
return staticIndexByName[name];
}
/// <summary>
/// Returns the index value for the given header field in the static table.
/// Returns -1 if the header field is not in the static table.
/// </summary>
/// <returns>The index.</returns>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
public static int GetIndex(string name, string value)
{
int index = GetIndex(name);
if (index == -1)
{
return -1;
}
// Note this assumes all entries for a given header field are sequential.
while (index <= Length)
{
var entry = Get(index);
if (!HpackUtil.Equals(name, entry.Name))
{
break;
}
if (HpackUtil.Equals(value, entry.Value))
{
return index;
}
index++;
}
return -1;
}
/// <summary>
/// create a map of header name to index value to allow quick lookup
/// </summary>
/// <returns>The map.</returns>
private static Dictionary<string, int> CreateMap()
{
int length = staticTable.Count;
var ret = new Dictionary<string, int>(length);
// Iterate through the static table in reverse order to
// save the smallest index for a given name in the map.
for (int index = length; index > 0; index--)
{
var entry = Get(index);
string name = entry.Name;
ret[name] = index;
}
return ret;
}
}
}
\ No newline at end of file
#if NETCOREAPP2_1
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http2.Hpack;
namespace Titanium.Web.Proxy.Http2
{
[Flags]
internal enum Http2FrameFlag
{
Ack = 0x01,
EndStream = 0x01,
EndHeaders = 0x04,
Padded = 0x08,
Priority = 0x20,
}
internal class Http2Helper
{
/// <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="connectionId"></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, Guid connectionId,
ExceptionHandler exceptionFunc)
{
// Now async relay all server=>client & client=>server data
var sendRelay =
CopyHttp2FrameAsync(clientStream, serverStream, onDataSend, bufferSize, connectionId,
true, cancellationTokenSource.Token);
var receiveRelay =
CopyHttp2FrameAsync(serverStream, clientStream, onDataReceive, bufferSize, connectionId,
false, 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, bool isClient, CancellationToken cancellationToken)
{
var decoder = new Decoder(8192, 4096);
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;
}
if (isClient)
{
if (type == 1 /*headers*/)
{
bool endHeaders = (flags & (int)Http2FrameFlag.EndHeaders) != 0;
bool padded = (flags & (int)Http2FrameFlag.Padded) != 0;
bool priority = (flags & (int)Http2FrameFlag.Priority) != 0;
System.Diagnostics.Debug.WriteLine("HEADER: " + streamId + " end: " + endHeaders);
int offset = 0;
if (padded)
{
offset = 1;
}
if (priority)
{
offset += 5;
}
int dataLength = length - offset;
if (padded)
{
dataLength -= buffer[0];
}
var headerListener = new MyHeaderListener();
try
{
decoder.Decode(new BinaryReader(new MemoryStream(buffer, offset, dataLength)),
headerListener);
decoder.EndHeaderBlock();
}
catch (Exception)
{
}
}
}
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;
}
class MyHeaderListener : IHeaderListener
{
public void AddHeader(string name, string value, bool sensitive)
{
Console.WriteLine(name + ": " + value + " " + sensitive);
}
}
}
}
#endif
\ No newline at end of file
......@@ -69,6 +69,15 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public int Port { get; set; }
/// <summary>
/// Get cache key for Tcp connection cahe.
/// </summary>
/// <returns></returns>
internal string GetCacheKey()
{
return $"{HostName}-{Port}" + (UseDefaultCredentials ? $"-{UserName}-{Password}" : string.Empty);
}
/// <summary>
/// returns data in Hostname:port format.
/// </summary>
......@@ -77,5 +86,6 @@ namespace Titanium.Web.Proxy.Models
{
return $"{HostName}:{Port}";
}
}
}
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Models
......@@ -12,6 +9,13 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public class HttpHeader
{
/// <summary>
/// HPACK: Header Compression for HTTP/2
/// Section 4.1. Calculating Table Size
/// The additional 32 octets account for an estimated overhead associated with an entry.
/// </summary>
public const int HttpHeaderOverhead = 32;
internal static readonly Version VersionUnknown = new Version(0, 0);
internal static readonly Version Version10 = new Version(1, 0);
......@@ -48,6 +52,13 @@ namespace Titanium.Web.Proxy.Models
/// </summary>
public string Value { get; set; }
public int Size => Name.Length + Value.Length + HttpHeaderOverhead;
public static int SizeOf(string name, string value)
{
return name.Length + value.Length + HttpHeaderOverhead;
}
/// <summary>
/// Returns header as a valid header string.
/// </summary>
......@@ -63,12 +74,5 @@ namespace Titanium.Web.Proxy.Models
"Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{userName}:{password}")));
return result;
}
internal async Task WriteToStreamAsync(HttpWriter writer, CancellationToken cancellationToken)
{
await writer.WriteAsync(Name, cancellationToken);
await writer.WriteAsync(": ", cancellationToken);
await writer.WriteLineAsync(Value, cancellationToken);
}
}
}
namespace Titanium.Web.Proxy.Models
{
public enum ProxyAuthenticationResult
{
/// <summary>
/// Indicates the authentication request was successful
/// </summary>
Success,
/// <summary>
/// Indicates the authentication request failed
/// </summary>
Failure,
/// <summary>
/// Indicates that this stage of the authentication request succeeded
/// And a second pass of the handshake needs to occur
/// </summary>
ContinuationNeeded
}
/// <summary>
/// A context container for authentication flows
/// </summary>
public class ProxyAuthenticationContext
{
/// <summary>
/// The result of the current authentication request
/// </summary>
public ProxyAuthenticationResult Result { get; set; }
/// <summary>
/// An optional continuation token to return to the caller if set
/// </summary>
public string Continuation { get; set; }
public static ProxyAuthenticationContext Failed()
{
return new ProxyAuthenticationContext
{
Result = ProxyAuthenticationResult.Failure,
Continuation = null
};
}
public static ProxyAuthenticationContext Succeeded()
{
return new ProxyAuthenticationContext
{
Result = ProxyAuthenticationResult.Success,
Continuation = null
};
}
}
}
......@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <returns>X509Certificate2 instance.</returns>
public X509Certificate2 MakeCertificate(string sSubjectCn, bool isRoot, X509Certificate2 signingCert = null)
{
return MakeCertificateInternal(sSubjectCn, isRoot, true, signingCert);
return makeCertificateInternal(sSubjectCn, isRoot, true, signingCert);
}
/// <summary>
......@@ -65,7 +65,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="hostName">The host name</param>
/// <returns>X509Certificate2 instance.</returns>
/// <exception cref="PemException">Malformed sequence in RSA private key</exception>
private static X509Certificate2 GenerateCertificate(string hostName,
private static X509Certificate2 generateCertificate(string hostName,
string subjectName,
string issuerName, DateTime validFrom,
DateTime validTo, int keyStrength = 2048,
......@@ -145,8 +145,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
#else
var x509Certificate = WithPrivateKey(certificate, rsaparams);
x509Certificate.FriendlyName = subjectName;
var x509Certificate = withPrivateKey(certificate, rsaparams);
#endif
if (!doNotSetFriendlyName)
......@@ -164,7 +163,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
return x509Certificate;
}
private static X509Certificate2 WithPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey)
private static X509Certificate2 withPrivateKey(X509Certificate certificate, AsymmetricKeyParameter privateKey)
{
const string password = "password";
var store = new Pkcs12Store();
......@@ -194,7 +193,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// You must specify a Signing Certificate if and only if you are not creating a
/// root.
/// </exception>
private X509Certificate2 MakeCertificateInternal(bool isRoot,
private X509Certificate2 makeCertificateInternal(bool isRoot,
string hostName, string subjectName,
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{
......@@ -207,11 +206,11 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (isRoot)
{
return GenerateCertificate(null, subjectName, subjectName, validFrom, validTo);
return generateCertificate(null, subjectName, subjectName, validFrom, validTo);
}
var kp = DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey);
return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo,
return generateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo,
issuerPrivateKey: kp.Private);
}
......@@ -224,7 +223,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="signingCert">The signing cert.</param>
/// <param name="cancellationToken">Task cancellation token</param>
/// <returns>X509Certificate2.</returns>
private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot,
private X509Certificate2 makeCertificateInternal(string subject, bool isRoot,
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default)
{
......@@ -238,7 +237,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
{
try
{
certificate = MakeCertificateInternal(subject, isRoot, false, signingCert);
certificate = makeCertificateInternal(subject, isRoot, false, signingCert);
}
catch (Exception ex)
{
......@@ -258,7 +257,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
}
#endif
return MakeCertificateInternal(isRoot, subject, $"CN={subject}",
return makeCertificateInternal(isRoot, subject, $"CN={subject}",
DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays),
isRoot ? null : signingCert);
}
......
......@@ -80,10 +80,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <returns></returns>
public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot, X509Certificate2 signingCert = null)
{
return MakeCertificateInternal(sSubjectCN, isRoot, true, signingCert);
return makeCertificateInternal(sSubjectCN, isRoot, true, signingCert);
}
private X509Certificate2 MakeCertificate(bool isRoot, string subject, string fullSubject,
private X509Certificate2 makeCertificate(bool isRoot, string subject, string fullSubject,
int privateKeyLength, string hashAlg, DateTime validFrom, DateTime validTo,
X509Certificate2 signingCertificate)
{
......@@ -274,13 +274,13 @@ namespace Titanium.Web.Proxy.Network.Certificate
return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
}
private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot,
private X509Certificate2 makeCertificateInternal(string sSubjectCN, bool isRoot,
bool switchToMTAIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default)
{
if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{
return Task.Run(() => MakeCertificateInternal(sSubjectCN, isRoot, false, signingCert),
return Task.Run(() => makeCertificateInternal(sSubjectCN, isRoot, false, signingCert),
cancellationToken).Result;
}
......@@ -301,7 +301,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
var graceTime = DateTime.Now.AddDays(graceDays);
var now = DateTime.Now;
var certificate = MakeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime,
var certificate = makeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime,
now.AddDays(validDays), isRoot ? null : signingCert);
return certificate;
}
......
......@@ -43,7 +43,6 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
private readonly ConcurrentDictionary<string, CachedCertificate> certificateCache;
private readonly ExceptionHandler exceptionFunc;
private readonly ConcurrentDictionary<string, Task<X509Certificate2>> pendingCertificateCreationTasks;
private ICertificateMaker certEngine;
......@@ -77,7 +76,7 @@ namespace Titanium.Web.Proxy.Network
bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin,
ExceptionHandler exceptionFunc)
{
this.exceptionFunc = exceptionFunc;
ExceptionFunc = exceptionFunc;
UserTrustRoot = userTrustRootCertificate || machineTrustRootCertificate;
......@@ -94,14 +93,7 @@ namespace Titanium.Web.Proxy.Network
RootCertificateIssuerName = rootCertificateIssuerName;
}
if (RunTime.IsWindows)
{
CertificateEngine = CertificateEngine.DefaultWindows;
}
else
{
CertificateEngine = CertificateEngine.BouncyCastle;
}
CertificateEngine = RunTime.IsWindows ? CertificateEngine.DefaultWindows : CertificateEngine.BouncyCastle;
certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
pendingCertificateCreationTasks = new ConcurrentDictionary<string, Task<X509Certificate2>>();
......@@ -131,6 +123,11 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
internal bool TrustRootAsAdministrator { get; set; }
/// <summary>
/// Exception handler
/// </summary>
internal ExceptionHandler ExceptionFunc { get; set; }
/// <summary>
/// Select Certificate Engine.
/// Optionally set to BouncyCastle.
......@@ -156,8 +153,8 @@ namespace Titanium.Web.Proxy.Network
if (certEngine == null)
{
certEngine = engine == CertificateEngine.BouncyCastle
? (ICertificateMaker)new BCCertificateMaker(exceptionFunc)
: new WinCertificateMaker(exceptionFunc);
? (ICertificateMaker)new BCCertificateMaker(ExceptionFunc)
: new WinCertificateMaker(ExceptionFunc);
}
}
}
......@@ -242,7 +239,7 @@ namespace Titanium.Web.Proxy.Network
{
}
private string GetRootCertificateDirectory()
private string getRootCertificateDirectory()
{
string assemblyLocation = Assembly.GetExecutingAssembly().Location;
......@@ -261,9 +258,9 @@ namespace Titanium.Web.Proxy.Network
return path;
}
private string GetCertificatePath()
private string getCertificatePath()
{
string path = GetRootCertificateDirectory();
string path = getRootCertificateDirectory();
string certPath = Path.Combine(path, "crts");
if (!Directory.Exists(certPath))
......@@ -274,9 +271,9 @@ namespace Titanium.Web.Proxy.Network
return certPath;
}
private string GetRootCertificatePath()
private string getRootCertificatePath()
{
string path = GetRootCertificateDirectory();
string path = getRootCertificateDirectory();
string fileName = PfxFilePath;
if (fileName == string.Empty)
......@@ -293,15 +290,15 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// <param name="storeLocation"></param>
/// <returns></returns>
private bool RootCertificateInstalled(StoreLocation storeLocation)
private bool rootCertificateInstalled(StoreLocation storeLocation)
{
string value = $"{RootCertificate.Issuer}";
return FindCertificates(StoreName.Root, storeLocation, value).Count > 0
return findCertificates(StoreName.Root, storeLocation, value).Count > 0
&& (CertificateEngine != CertificateEngine.DefaultWindows
|| FindCertificates(StoreName.My, storeLocation, value).Count > 0);
|| findCertificates(StoreName.My, storeLocation, value).Count > 0);
}
private X509Certificate2Collection FindCertificates(StoreName storeName, StoreLocation storeLocation,
private static X509Certificate2Collection findCertificates(StoreName storeName, StoreLocation storeLocation,
string findValue)
{
var x509Store = new X509Store(storeName, storeLocation);
......@@ -321,11 +318,11 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
/// <param name="storeName"></param>
/// <param name="storeLocation"></param>
private void InstallCertificate(StoreName storeName, StoreLocation storeLocation)
private void installCertificate(StoreName storeName, StoreLocation storeLocation)
{
if (RootCertificate == null)
{
exceptionFunc(new Exception("Could not install certificate as it is null or empty."));
ExceptionFunc(new Exception("Could not install certificate as it is null or empty."));
return;
}
......@@ -340,7 +337,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(
ExceptionFunc(
new Exception("Failed to make system trust root certificate "
+ $" for {storeName}\\{storeLocation} store location. You may need admin rights.",
e));
......@@ -357,12 +354,12 @@ namespace Titanium.Web.Proxy.Network
/// <param name="storeName"></param>
/// <param name="storeLocation"></param>
/// <param name="certificate"></param>
private void UninstallCertificate(StoreName storeName, StoreLocation storeLocation,
private void uninstallCertificate(StoreName storeName, StoreLocation storeLocation,
X509Certificate2 certificate)
{
if (certificate == null)
{
exceptionFunc(new Exception("Could not remove certificate as it is null or empty."));
ExceptionFunc(new Exception("Could not remove certificate as it is null or empty."));
return;
}
......@@ -376,7 +373,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(
ExceptionFunc(
new Exception("Failed to remove root certificate trust "
+ $" for {storeLocation} store location. You may need admin rights.", e));
}
......@@ -386,7 +383,7 @@ namespace Titanium.Web.Proxy.Network
}
}
private X509Certificate2 MakeCertificate(string certificateName, bool isRootCertificate)
private X509Certificate2 makeCertificate(string certificateName, bool isRootCertificate)
{
if (!isRootCertificate && RootCertificate == null)
{
......@@ -397,7 +394,7 @@ namespace Titanium.Web.Proxy.Network
if (CertificateEngine == CertificateEngine.DefaultWindows)
{
Task.Run(() => UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, certificate));
Task.Run(() => uninstallCertificate(StoreName.My, StoreLocation.CurrentUser, certificate));
}
return certificate;
......@@ -416,14 +413,14 @@ namespace Titanium.Web.Proxy.Network
{
if (!isRootCertificate && SaveFakeCertificates)
{
string path = GetCertificatePath();
string path = getCertificatePath();
string subjectName = ProxyConstants.CNRemoverRegex.Replace(certificateName, string.Empty);
subjectName = subjectName.Replace("*", "$x$");
string certificatePath = Path.Combine(path, subjectName + ".pfx");
if (!File.Exists(certificatePath))
{
certificate = MakeCertificate(certificateName, false);
certificate = makeCertificate(certificateName, false);
// store as cache
Task.Run(() =>
......@@ -434,7 +431,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(new Exception("Failed to save fake certificate.", e));
ExceptionFunc(new Exception("Failed to save fake certificate.", e));
}
});
}
......@@ -447,18 +444,18 @@ namespace Titanium.Web.Proxy.Network
catch
{
// if load failed create again
certificate = MakeCertificate(certificateName, false);
certificate = makeCertificate(certificateName, false);
}
}
}
else
{
certificate = MakeCertificate(certificateName, isRootCertificate);
certificate = makeCertificate(certificateName, isRootCertificate);
}
}
catch (Exception e)
{
exceptionFunc(e);
ExceptionFunc(e);
}
return certificate;
......@@ -568,7 +565,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(e);
ExceptionFunc(e);
}
if (persistToFile && RootCertificate != null)
......@@ -577,19 +574,19 @@ namespace Titanium.Web.Proxy.Network
{
try
{
Directory.Delete(GetCertificatePath(), true);
Directory.Delete(getCertificatePath(), true);
}
catch
{
// ignore
}
string fileName = GetRootCertificatePath();
string fileName = getRootCertificatePath();
File.WriteAllBytes(fileName, RootCertificate.Export(X509ContentType.Pkcs12, PfxPassword));
}
catch (Exception e)
{
exceptionFunc(e);
ExceptionFunc(e);
}
}
......@@ -602,7 +599,7 @@ namespace Titanium.Web.Proxy.Network
/// <returns></returns>
public X509Certificate2 LoadRootCertificate()
{
string fileName = GetRootCertificatePath();
string fileName = getRootCertificatePath();
pfxFileExists = File.Exists(fileName);
if (!pfxFileExists)
{
......@@ -615,7 +612,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(e);
ExceptionFunc(e);
return null;
}
}
......@@ -656,20 +653,20 @@ namespace Titanium.Web.Proxy.Network
public void TrustRootCertificate(bool machineTrusted = false)
{
// currentUser\personal
InstallCertificate(StoreName.My, StoreLocation.CurrentUser);
installCertificate(StoreName.My, StoreLocation.CurrentUser);
if (!machineTrusted)
{
// currentUser\Root
InstallCertificate(StoreName.Root, StoreLocation.CurrentUser);
installCertificate(StoreName.Root, StoreLocation.CurrentUser);
}
else
{
// current system
InstallCertificate(StoreName.My, StoreLocation.LocalMachine);
installCertificate(StoreName.My, StoreLocation.LocalMachine);
// this adds to both currentUser\Root & currentMachine\Root
InstallCertificate(StoreName.Root, StoreLocation.LocalMachine);
installCertificate(StoreName.Root, StoreLocation.LocalMachine);
}
}
......@@ -686,7 +683,7 @@ namespace Titanium.Web.Proxy.Network
}
// currentUser\Personal
InstallCertificate(StoreName.My, StoreLocation.CurrentUser);
installCertificate(StoreName.My, StoreLocation.CurrentUser);
string pfxFileName = Path.GetTempFileName();
File.WriteAllBytes(pfxFileName, RootCertificate.Export(X509ContentType.Pkcs12, PfxPassword));
......@@ -724,7 +721,7 @@ namespace Titanium.Web.Proxy.Network
}
catch (Exception e)
{
exceptionFunc(e);
ExceptionFunc(e);
return false;
}
......@@ -781,7 +778,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
public bool IsRootCertificateUserTrusted()
{
return RootCertificateInstalled(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
return rootCertificateInstalled(StoreLocation.CurrentUser) || IsRootCertificateMachineTrusted();
}
/// <summary>
......@@ -789,7 +786,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary>
public bool IsRootCertificateMachineTrusted()
{
return RootCertificateInstalled(StoreLocation.LocalMachine);
return rootCertificateInstalled(StoreLocation.LocalMachine);
}
/// <summary>
......@@ -800,20 +797,20 @@ namespace Titanium.Web.Proxy.Network
public void RemoveTrustedRootCertificate(bool machineTrusted = false)
{
// currentUser\personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
uninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
if (!machineTrusted)
{
// currentUser\Root
UninstallCertificate(StoreName.Root, StoreLocation.CurrentUser, RootCertificate);
uninstallCertificate(StoreName.Root, StoreLocation.CurrentUser, RootCertificate);
}
else
{
// current system
UninstallCertificate(StoreName.My, StoreLocation.LocalMachine, RootCertificate);
uninstallCertificate(StoreName.My, StoreLocation.LocalMachine, RootCertificate);
// this adds to both currentUser\Root & currentMachine\Root
UninstallCertificate(StoreName.Root, StoreLocation.LocalMachine, RootCertificate);
uninstallCertificate(StoreName.Root, StoreLocation.LocalMachine, RootCertificate);
}
}
......@@ -829,7 +826,7 @@ namespace Titanium.Web.Proxy.Network
}
// currentUser\Personal
UninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
uninstallCertificate(StoreName.My, StoreLocation.CurrentUser, RootCertificate);
var infos = new List<ProcessStartInfo>();
if (!machineTrusted)
......
......@@ -3,6 +3,7 @@ using System;
using System.IO;
using System.Text;
using System.Threading;
using StreamExtended;
using StreamExtended.Network;
namespace Titanium.Web.Proxy.Network
......@@ -17,7 +18,8 @@ namespace Titanium.Web.Proxy.Network
private readonly FileStream fileStreamSent;
public DebugCustomBufferedStream(Guid connectionId, string type, Stream baseStream, int bufferSize, bool leaveOpen = false) : base(baseStream, bufferSize, leaveOpen)
public DebugCustomBufferedStream(Guid connectionId, string type, Stream baseStream, IBufferPool bufferPool, int bufferSize, bool leaveOpen = false)
: base(baseStream, bufferPool, bufferSize, leaveOpen)
{
Counter = Interlocked.Increment(ref counter);
fileStreamSent = new FileStream(Path.Combine(basePath, $"{connectionId}_{type}_{Counter}_sent.dat"), FileMode.Create);
......
using System;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy.Network
{
internal class RetryPolicy<T> where T : Exception
{
private readonly int retries;
private readonly TcpConnectionFactory tcpConnectionFactory;
private TcpServerConnection currentConnection;
internal RetryPolicy(int retries, TcpConnectionFactory tcpConnectionFactory)
{
this.retries = retries;
this.tcpConnectionFactory = tcpConnectionFactory;
}
/// <summary>
/// Execute and retry the given action until retry number of times.
/// </summary>
/// <param name="action">The action to retry with return value specifying whether caller should continue execution.</param>
/// <param name="generator">The Tcp connection generator to be invoked to get new connection for retry.</param>
/// <param name="initialConnection">Initial Tcp connection to use.</param>
/// <returns>Returns the latest connection used and the latest exception if any.</returns>
internal async Task<RetryResult> ExecuteAsync(Func<TcpServerConnection, Task<bool>> action,
Func<Task<TcpServerConnection>> generator, TcpServerConnection initialConnection)
{
currentConnection = initialConnection;
bool @continue = true;
Exception exception = null;
var attempts = retries;
while (true)
{
try
{
//setup connection
currentConnection = currentConnection as TcpServerConnection ??
await generator();
//try
@continue = await action(currentConnection);
}
catch (Exception ex)
{
exception = ex;
}
attempts--;
if (attempts < 0
|| exception == null
|| !(exception is T))
{
break;
}
exception = null;
await disposeConnection();
}
return new RetryResult(currentConnection, exception, @continue);
}
//before retry clear connection
private async Task disposeConnection()
{
if (currentConnection != null)
{
//close connection on error
await tcpConnectionFactory.Release(currentConnection, true);
currentConnection = null;
}
}
}
internal class RetryResult
{
internal bool IsSuccess => Exception == null;
internal TcpServerConnection LatestConnection { get; }
internal Exception Exception { get; }
internal bool Continue { get; }
internal RetryResult(TcpServerConnection lastConnection, Exception exception, bool @continue)
{
LatestConnection = lastConnection;
Exception = exception;
Continue = @continue;
}
}
}
using System;
using System.IO;
using System.Net;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Net.Sockets;
using Titanium.Web.Proxy.Extensions;
......@@ -41,9 +43,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
public void Dispose()
{
tcpClient.CloseSocket();
proxyServer.UpdateClientConnectionCount(false);
tcpClient.CloseSocket();
}
}
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
......@@ -14,29 +18,233 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network.Tcp
{
/// <summary>
/// A class that manages Tcp Connection to server used by this proxy server
/// A class that manages Tcp Connection to server used by this proxy server.
/// </summary>
internal class TcpConnectionFactory
internal class TcpConnectionFactory : IDisposable
{
//Tcp server connection pool cache
private readonly ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>> cache
= new ConcurrentDictionary<string, ConcurrentQueue<TcpServerConnection>>();
//Tcp connections waiting to be disposed by cleanup task
private readonly ConcurrentBag<TcpServerConnection> disposalBag =
new ConcurrentBag<TcpServerConnection>();
//cache object race operations lock
private readonly SemaphoreSlim @lock = new SemaphoreSlim(1);
private volatile bool runCleanUpTask = true;
internal TcpConnectionFactory(ProxyServer server)
{
this.server = server;
Task.Run(async () => await clearOutdatedConnections());
}
internal ProxyServer server { get; set; }
internal string GetConnectionCacheKey(string remoteHostName, int remotePort,
bool isHttps, List<SslApplicationProtocol> applicationProtocols,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy)
{
//http version is ignored since its an application level decision b/w HTTP 1.0/1.1
//also when doing connect request MS Edge browser sends http 1.0 but uses 1.1 after server sends 1.1 its response.
//That can create cache miss for same server connection unneccessarily expecially when prefetcing with Connect.
//http version 2 is separated using applicationProtocols below.
var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" +
//when creating Tcp client isConnect won't matter
$"{isHttps}-");
if (applicationProtocols != null)
{
foreach (var protocol in applicationProtocols.OrderBy(x => x))
{
cacheKeyBuilder.Append($"{protocol}-");
}
}
cacheKeyBuilder.Append(upStreamEndPoint != null
? $"{upStreamEndPoint.Address}-{upStreamEndPoint.Port}-"
: string.Empty);
cacheKeyBuilder.Append(externalProxy != null ? $"{externalProxy.GetCacheKey()}-" : string.Empty);
return cacheKeyBuilder.ToString();
}
/// <summary>
/// Creates a TCP connection to server
/// Gets the connection cache key.
/// </summary>
/// <param name="remoteHostName"></param>
/// <param name="remotePort"></param>
/// <param name="httpVersion"></param>
/// <param name="decryptSsl"></param>
/// <param name="args">The session event arguments.</param>
/// <param name="applicationProtocol"></param>
/// <returns></returns>
internal async Task<string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args,
SslApplicationProtocol applicationProtocol)
{
List<SslApplicationProtocol> applicationProtocols = null;
if (applicationProtocol != default)
{
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
return GetConnectionCacheKey(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
isHttps, applicationProtocols,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy));
}
/// <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="applicationProtocol"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
internal Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect,
SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken)
{
List<SslApplicationProtocol> applicationProtocols = null;
if (applicationProtocol != default)
{
applicationProtocols = new List<SslApplicationProtocol> { applicationProtocol };
}
return GetServerConnection(server, args, isConnect, applicationProtocols, noCache, 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="isConnect"></param>
/// <param name="proxyServer"></param>
/// <param name="upStreamEndPoint"></param>
/// <param name="externalProxy"></param>
/// <param name="cancellationToken"></param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
internal async Task<TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, bool noCache, CancellationToken cancellationToken)
{
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
if (server.GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
return await GetServerConnection(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion,
isHttps, applicationProtocols, isConnect,
server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy),
noCache, cancellationToken);
}
/// <summary>
/// Gets a TCP connection to server from connection pool.
/// </summary>
/// <param name="remoteHostName">The remote hostname.</param>
/// <param name="remotePort">The remote port.</param>
/// <param name="httpVersion">The http version to use.</param>
/// <param name="isHttps">Is this a HTTPS request.</param>
/// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="noCache">Not from cache/create new connection.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
internal async Task<TcpServerConnection> CreateClient(string remoteHostName, int remotePort,
Version httpVersion, bool decryptSsl, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
internal async Task<TcpServerConnection> GetServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
bool noCache, CancellationToken cancellationToken)
{
var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort,
isHttps, applicationProtocols,
proxyServer, upStreamEndPoint, externalProxy);
if (proxyServer.EnableConnectionPool && !noCache)
{
if (cache.TryGetValue(cacheKey, out var existingConnections))
{
while (existingConnections.Count > 0)
{
if (existingConnections.TryDequeue(out var recentConnection))
{
//+3 seconds for potential delay after getting connection
var cutOff = DateTime.Now.AddSeconds(-1 * proxyServer.ConnectionTimeOutSeconds + 3);
if (recentConnection.LastAccess > cutOff
&& isGoodConnection(recentConnection.TcpClient))
{
return recentConnection;
}
disposalBag.Add(recentConnection);
}
}
}
}
var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps,
applicationProtocols, isConnect, proxyServer, upStreamEndPoint, externalProxy, cancellationToken);
connection.CacheKey = cacheKey;
return connection;
}
/// <summary>
/// Creates a TCP connection to server
/// </summary>
/// <param name="remoteHostName">The remote hostname.</param>
/// <param name="remotePort">The remote port.</param>
/// <param name="httpVersion">The http version to use.</param>
/// <param name="isHttps">Is this a HTTPS request.</param>
/// <param name="applicationProtocols">The list of HTTPS application level protocol to negotiate if needed.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="proxyServer">The current ProxyServer instance.</param>
/// <param name="upStreamEndPoint">The local upstream endpoint to make request via.</param>
/// <param name="externalProxy">The external proxy to make request via.</param>
/// <param name="cancellationToken">The cancellation token for this async task.</param>
/// <returns></returns>
private async Task<TcpServerConnection> createServerConnection(string remoteHostName, int remotePort,
Version httpVersion, bool isHttps, List<SslApplicationProtocol> applicationProtocols, bool isConnect,
ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy,
CancellationToken cancellationToken)
{
//deny connection to proxy end points to avoid infinite connection loop.
if (server.ProxyEndPoints.Any(x => x.Port == remotePort)
&& NetworkHelper.IsLocalIpAddress(remoteHostName))
{
throw new Exception($"A client is making HTTP request to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
}
if (externalProxy != null)
{
if (server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port)
&& NetworkHelper.IsLocalIpAddress(externalProxy.HostName))
{
throw new Exception($"A client is making HTTP request via external proxy to one of the listening ports of this proxy {remoteHostName}:{remotePort}");
}
}
bool useUpstreamProxy = false;
// check if external proxy is set for HTTP/HTTPS
......@@ -59,7 +267,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
try
{
tcpClient = new TcpClient(upStreamEndPoint);
tcpClient = new TcpClient(upStreamEndPoint)
{
ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000,
SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000,
SendBufferSize = proxyServer.BufferSize,
ReceiveBufferSize = proxyServer.BufferSize
};
// If this proxy uses another external proxy then create a tunnel request for HTTP/HTTPS connections
if (useUpstreamProxy)
......@@ -71,11 +285,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
await tcpClient.ConnectAsync(remoteHostName, remotePort);
}
stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferSize);
await proxyServer.InvokeConnectionCreateEvent(tcpClient, false);
if (useUpstreamProxy && (isConnect || decryptSsl))
stream = new CustomBufferedStream(tcpClient.GetStream(), proxyServer.BufferPool, proxyServer.BufferSize);
if (useUpstreamProxy && (isConnect || isHttps))
{
var writer = new HttpRequestWriter(stream, proxyServer.BufferSize);
var writer = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize);
var connectRequest = new ConnectRequest
{
OriginalUrl = $"{remoteHostName}:{remotePort}",
......@@ -106,26 +322,25 @@ namespace Titanium.Web.Proxy.Network.Tcp
await stream.ReadAndIgnoreAllLinesAsync(cancellationToken);
}
if (decryptSsl)
if (isHttps)
{
var sslStream = new SslStream(stream, false, proxyServer.ValidateServerCertificate,
proxyServer.SelectClientCertificate);
stream = new CustomBufferedStream(sslStream, proxyServer.BufferSize);
var options = new SslClientAuthenticationOptions();
options.ApplicationProtocols = applicationProtocols;
options.TargetHost = remoteHostName;
options.ClientCertificates = null;
options.EnabledSslProtocols = proxyServer.SupportedSslProtocols;
options.CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation;
stream = new CustomBufferedStream(sslStream, proxyServer.BufferPool, proxyServer.BufferSize);
var options = new SslClientAuthenticationOptions
{
ApplicationProtocols = applicationProtocols,
TargetHost = remoteHostName,
ClientCertificates = null,
EnabledSslProtocols = proxyServer.SupportedSslProtocols,
CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation
};
await sslStream.AuthenticateAsClientAsync(options, cancellationToken);
#if NETCOREAPP2_1
negotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif
}
tcpClient.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
tcpClient.SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000;
}
catch (Exception)
{
......@@ -140,13 +355,226 @@ namespace Titanium.Web.Proxy.Network.Tcp
UpStreamEndPoint = upStreamEndPoint,
HostName = remoteHostName,
Port = remotePort,
IsHttps = decryptSsl,
IsHttps = isHttps,
NegotiatedApplicationProtocol = negotiatedApplicationProtocol,
UseUpstreamProxy = useUpstreamProxy,
StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferSize),
StreamWriter = new HttpRequestWriter(stream, proxyServer.BufferPool, proxyServer.BufferSize),
Stream = stream,
Version = httpVersion
};
}
/// <summary>
/// Release connection back to cache.
/// </summary>
/// <param name="connection">The Tcp server connection to return.</param>
/// <param name="close">Should we just close the connection instead of reusing?</param>
internal async Task Release(TcpServerConnection connection, bool close = false)
{
if (connection == null)
{
return;
}
if (close || connection.IsWinAuthenticated || !server.EnableConnectionPool)
{
disposalBag.Add(connection);
return;
}
connection.LastAccess = DateTime.Now;
try
{
await @lock.WaitAsync();
while (true)
{
if (cache.TryGetValue(connection.CacheKey, out var existingConnections))
{
while (existingConnections.Count >= server.MaxCachedConnections)
{
if (existingConnections.TryDequeue(out var staleConnection))
{
disposalBag.Add(staleConnection);
}
}
existingConnections.Enqueue(connection);
break;
}
if (cache.TryAdd(connection.CacheKey,
new ConcurrentQueue<TcpServerConnection>(new[] { connection })))
{
break;
}
}
}
finally
{
@lock.Release();
}
}
internal async Task Release(Task<TcpServerConnection> connectionCreateTask, bool closeServerConnection)
{
if (connectionCreateTask != null)
{
TcpServerConnection connection = null;
try
{
connection = await connectionCreateTask;
}
catch { }
finally
{
await Release(connection, closeServerConnection);
}
}
}
private async Task clearOutdatedConnections()
{
while (runCleanUpTask)
{
try
{
foreach (var item in cache)
{
var queue = item.Value;
while (queue.Count > 0)
{
if (queue.TryDequeue(out var connection))
{
var cutOff = DateTime.Now.AddSeconds(-1 * server.ConnectionTimeOutSeconds);
if (!server.EnableConnectionPool
|| connection.LastAccess < cutOff)
{
disposalBag.Add(connection);
continue;
}
queue.Enqueue(connection);
break;
}
}
}
try
{
await @lock.WaitAsync();
//clear empty queues
var emptyKeys = cache.Where(x => x.Value.Count == 0).Select(x => x.Key).ToList();
foreach (string key in emptyKeys)
{
cache.TryRemove(key, out var _);
}
}
finally
{
@lock.Release();
}
while (!disposalBag.IsEmpty)
{
if (disposalBag.TryTake(out var connection))
{
connection?.Dispose();
}
}
}
catch (Exception e)
{
server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e));
}
finally
{
//cleanup every 3 seconds by default
await Task.Delay(1000 * 3);
}
}
}
/// <summary>
/// Check if a TcpClient is good to be used.
/// This only checks if send is working so local socket is still connected.
/// Receive can only be verified by doing a valid read from server without exceptions.
/// So in our case we should retry with new connection from pool if first read after getting the connection fails.
/// https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected(v=vs.110).aspx
/// </summary>
/// <param name="client"></param>
/// <returns></returns>
private static bool isGoodConnection(TcpClient client)
{
var socket = client.Client;
if (!client.Connected || !socket.Connected)
{
return false;
}
// This is how you can determine whether a socket is still connected.
bool blockingState = socket.Blocking;
try
{
var tmp = new byte[1];
socket.Blocking = false;
socket.Send(tmp, 0, 0);
//Connected.
}
catch
{
//Should we let 10035 == WSAEWOULDBLOCK as valid connection?
return false;
}
finally
{
socket.Blocking = blockingState;
}
return true;
}
public void Dispose()
{
runCleanUpTask = false;
try
{
@lock.Wait();
foreach (var queue in cache.Select(x => x.Value).ToList())
{
while (!queue.IsEmpty)
{
if (queue.TryDequeue(out var connection))
{
disposalBag.Add(connection);
}
}
}
cache.Clear();
}
finally
{
@lock.Release();
}
while (!disposalBag.IsEmpty)
{
if (disposalBag.TryTake(out var connection))
{
connection?.Dispose();
}
}
}
}
}
using System;
using System.Net;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Net.Sockets;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions;
......@@ -48,6 +50,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
private readonly TcpClient tcpClient;
/// <summary>
/// The TcpClient.
/// </summary>
internal TcpClient TcpClient => tcpClient;
/// <summary>
/// Used to write lines to server
/// </summary>
......@@ -63,16 +70,24 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal DateTime LastAccess { get; set; }
/// <summary>
/// The cache key used to uniquely identify this connection properties
/// </summary>
internal string CacheKey { get; set; }
/// <summary>
/// Is this connection authenticated via WinAuth
/// </summary>
internal bool IsWinAuthenticated { get; set; }
/// <summary>
/// Dispose.
/// </summary>
public void Dispose()
{
proxyServer.UpdateServerConnectionCount(false);
Stream?.Dispose();
tcpClient.CloseSocket();
proxyServer.UpdateServerConnectionCount(false);
}
}
}
......@@ -18,10 +18,10 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="session">The session event arguments.</param>
/// <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 (AuthenticateUserFunc == null)
if (ProxyBasicAuthenticateFunc == null && ProxySchemeAuthenticateFunc == null)
{
return true;
}
......@@ -33,37 +33,39 @@ namespace Titanium.Web.Proxy
var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization);
if (header == null)
{
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Required");
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Required");
return false;
}
var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit);
if (headerValueParts.Length != 2 ||
!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
if (headerValueParts.Length != 2)
{
// Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid");
return false;
}
string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1]));
int colonIndex = decoded.IndexOf(':');
if (colonIndex == -1)
if (ProxyBasicAuthenticateFunc != null)
{
// Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false;
return await authenticateUserBasic(session, headerValueParts);
}
string username = decoded.Substring(0, colonIndex);
string password = decoded.Substring(colonIndex + 1);
bool authenticated = await AuthenticateUserFunc(username, password);
if (!authenticated)
if (ProxySchemeAuthenticateFunc != null)
{
var result = await ProxySchemeAuthenticateFunc(session, headerValueParts[0], headerValueParts[1]);
if (result.Result == ProxyAuthenticationResult.ContinuationNeeded)
{
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid", result.Continuation);
return false;
}
return authenticated;
return result.Result == ProxyAuthenticationResult.Success;
}
return false;
}
catch (Exception e)
{
......@@ -71,17 +73,46 @@ namespace Titanium.Web.Proxy
httpHeaders));
// Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid");
return false;
}
}
private async Task<bool> authenticateUserBasic(SessionEventArgsBase session, string[] headerValueParts)
{
if (!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
{
// Return not authorized
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid");
return false;
}
string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1]));
int colonIndex = decoded.IndexOf(':');
if (colonIndex == -1)
{
// Return not authorized
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid");
return false;
}
string username = decoded.Substring(0, colonIndex);
string password = decoded.Substring(colonIndex + 1);
bool authenticated = await ProxyBasicAuthenticateFunc(session, username, password);
if (!authenticated)
{
session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid");
}
return authenticated;
}
/// <summary>
/// Create an authentication required response.
/// </summary>
/// <param name="description">Response description.</param>
/// <returns></returns>
private Response CreateAuthentication407Response(string description)
private Response createAuthentication407Response(string description, string continuation = null)
{
var response = new Response
{
......@@ -90,11 +121,39 @@ namespace Titanium.Web.Proxy
StatusDescription = description
};
response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, $"Basic realm=\"{ProxyRealm}\"");
if (!string.IsNullOrWhiteSpace(continuation))
{
return createContinuationResponse(response, continuation);
}
if (ProxyBasicAuthenticateFunc != null)
{
response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, $"Basic realm=\"{ProxyAuthenticationRealm}\"");
}
if (ProxySchemeAuthenticateFunc != null)
{
foreach (var scheme in ProxyAuthenticationSchemes)
{
response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, scheme);
}
}
response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ProxyConnectionClose);
response.Headers.FixProxyHeaders();
return response;
}
private Response createContinuationResponse(Response response, string continuation)
{
response.Headers.AddHeader(KnownHeaders.ProxyAuthenticate, continuation);
response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ConnectionKeepAlive);
response.Headers.FixProxyHeaders();
return response;
}
}
}
......@@ -7,6 +7,7 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
......@@ -15,7 +16,6 @@ using Titanium.Web.Proxy.Helpers.WinHttp;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.Network.WinAuth.Security;
namespace Titanium.Web.Proxy
{
......@@ -97,8 +97,13 @@ namespace Titanium.Web.Proxy
// default values
ConnectionTimeOutSeconds = 60;
if (BufferPool == null)
{
BufferPool = new DefaultBufferPool();
}
ProxyEndPoints = new List<ProxyEndPoint>();
tcpConnectionFactory = new TcpConnectionFactory();
tcpConnectionFactory = new TcpConnectionFactory(this);
if (!RunTime.IsRunningOnMono && RunTime.IsWindows)
{
systemProxySettingsManager = new SystemProxyManager();
......@@ -118,6 +123,9 @@ namespace Titanium.Web.Proxy
/// </summary>
private SystemProxyManager systemProxySettingsManager { get; }
//Number of exception retries when connection pool is enabled.
private int retries => EnableConnectionPool ? MaxCachedConnections : 0;
/// <summary>
/// Is the proxy currently running?
/// </summary>
......@@ -125,6 +133,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Gets or sets a value indicating whether requests will be chained to upstream gateway.
/// Defaults to false.
/// </summary>
public bool ForwardToUpstreamGateway { get; set; }
......@@ -133,6 +142,7 @@ namespace Titanium.Web.Proxy
/// Note: NTLM/Kerberos will always send local credentials of current user
/// running the proxy process. This is because a man
/// in middle attack with Windows domain authentication is not currently supported.
/// Defaults to false.
/// </summary>
public bool EnableWinAuth { get; set; }
......@@ -150,15 +160,32 @@ namespace Titanium.Web.Proxy
public bool Enable100ContinueBehaviour { get; set; }
/// <summary>
/// Buffer size used throughout this proxy.
/// Should we enable experimental server connection pool?
/// Defaults to disable.
/// </summary>
public bool EnableConnectionPool { get; set; }
/// <summary>
/// Buffer size in bytes used throughout this proxy.
/// Default value is 8192 bytes.
/// </summary>
public int BufferSize { get; set; } = 8192;
/// <summary>
/// Seconds client/server connection are to be kept alive when waiting for read/write to complete.
/// This will also determine the pool eviction time when connection pool is enabled.
/// Default value is 60 seconds.
/// </summary>
public int ConnectionTimeOutSeconds { get; set; }
/// <summary>
/// Maximum number of concurrent connections per remote host in cache.
/// Only valid when connection pooling is enabled.
/// Default value is 2.
/// </summary>
public int MaxCachedConnections { get; set; } = 2;
/// <summary>
/// Total number of active client connections.
/// </summary>
......@@ -172,7 +199,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Realm used during Proxy Basic Authentication.
/// </summary>
public string ProxyRealm { get; set; } = "TitaniumProxy";
public string ProxyAuthenticationRealm { get; set; } = "TitaniumProxy";
/// <summary>
/// List of supported Ssl versions.
......@@ -183,6 +210,13 @@ namespace Titanium.Web.Proxy
#endif
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
/// <summary>
/// The buffer pool used throughout this proxy instance.
/// Set custom implementations by implementing this interface.
/// By default this uses DefaultBufferPool implementation available in StreamExtended library package.
/// </summary>
public IBufferPool BufferPool { get; set; }
/// <summary>
/// Manages certificates used by this proxy.
/// </summary>
......@@ -221,15 +255,32 @@ namespace Titanium.Web.Proxy
public ExceptionHandler ExceptionFunc
{
get => exceptionFunc ?? defaultExceptionFunc;
set => exceptionFunc = value;
set
{
exceptionFunc = value;
CertificateManager.ExceptionFunc = value;
}
}
/// <summary>
/// A callback to authenticate clients.
/// A callback to authenticate proxy clients via basic authentication.
/// Parameters are username and password as provided by client.
/// Should return true for successful authentication.
/// </summary>
public Func<string, string, Task<bool>> AuthenticateUserFunc { get; set; }
public Func<SessionEventArgsBase, string, string, Task<bool>> ProxyBasicAuthenticateFunc { get; set; }
/// <summary>
/// A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc.
/// Parameters are current working session, schemeType, and token as provided by a calling client.
/// Should return success for successful authentication, continuation if the package requests, or failure.
/// </summary>
public Func<SessionEventArgsBase, string, string, Task<ProxyAuthenticationContext>> ProxySchemeAuthenticateFunc { get; set; }
/// <summary>
/// A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required.
/// Works in relation with ProxySchemeAuthenticateFunc.
/// </summary>
public IEnumerable<string> ProxyAuthenticationSchemes { get; set; } = new string[0];
/// <summary>
/// Dispose the Proxy instance.
......@@ -242,6 +293,7 @@ namespace Titanium.Web.Proxy
}
CertificateManager?.Dispose();
BufferPool?.Dispose();
}
/// <summary>
......@@ -279,6 +331,16 @@ namespace Titanium.Web.Proxy
/// </summary>
public event AsyncEventHandler<SessionEventArgs> AfterResponse;
/// <summary>
/// Customize TcpClient used for client connection upon create.
/// </summary>
public event AsyncEventHandler<TcpClient> OnClientConnectionCreate;
/// <summary>
/// Customize TcpClient used for server connection upon create.
/// </summary>
public event AsyncEventHandler<TcpClient> OnServerConnectionCreate;
/// <summary>
/// Add a proxy end point.
/// </summary>
......@@ -295,7 +357,7 @@ namespace Titanium.Web.Proxy
if (ProxyRunning)
{
Listen(endPoint);
listen(endPoint);
}
}
......@@ -315,7 +377,7 @@ namespace Titanium.Web.Proxy
if (ProxyRunning)
{
QuitListen(endPoint);
quitListen(endPoint);
}
}
......@@ -349,7 +411,7 @@ namespace Titanium.Web.Proxy
throw new Exception("Mono Runtime do not support system proxy settings.");
}
ValidateEndPointAsSystemProxy(endPoint);
validateEndPointAsSystemProxy(endPoint);
bool isHttp = (protocolType & ProxyProtocolType.Http) > 0;
bool isHttps = (protocolType & ProxyProtocolType.Https) > 0;
......@@ -380,7 +442,7 @@ namespace Titanium.Web.Proxy
systemProxySettingsManager.SetProxy(
Equals(endPoint.IpAddress, IPAddress.Any) |
Equals(endPoint.IpAddress, IPAddress.Loopback)
? "127.0.0.1"
? "localhost"
: endPoint.IpAddress.ToString(),
endPoint.Port,
protocolType);
......@@ -483,8 +545,7 @@ namespace Titanium.Web.Proxy
var protocolToRemove = ProxyProtocolType.None;
foreach (var proxy in proxyInfo.Proxies.Values)
{
if ((proxy.HostName == "127.0.0.1"
|| proxy.HostName.EqualsIgnoreCase("localhost"))
if (NetworkHelper.IsLocalIpAddress(proxy.HostName)
&& ProxyEndPoints.Any(x => x.Port == proxy.Port))
{
protocolToRemove |= proxy.ProtocolType;
......@@ -504,7 +565,7 @@ namespace Titanium.Web.Proxy
systemProxyResolver = new WinHttpWebProxyFinder();
systemProxyResolver.LoadFromIE();
GetCustomUpStreamProxyFunc = GetSystemUpStreamProxy;
GetCustomUpStreamProxyFunc = getSystemUpStreamProxy;
}
ProxyRunning = true;
......@@ -513,7 +574,7 @@ namespace Titanium.Web.Proxy
foreach (var endPoint in ProxyEndPoints)
{
Listen(endPoint);
listen(endPoint);
}
}
......@@ -540,12 +601,13 @@ namespace Titanium.Web.Proxy
foreach (var endPoint in ProxyEndPoints)
{
QuitListen(endPoint);
quitListen(endPoint);
}
ProxyEndPoints.Clear();
CertificateManager?.StopClearIdleCertificates();
tcpConnectionFactory.Dispose();
ProxyRunning = false;
}
......@@ -554,7 +616,7 @@ namespace Titanium.Web.Proxy
/// Listen on given end point of local machine.
/// </summary>
/// <param name="endPoint">The end point to listen.</param>
private void Listen(ProxyEndPoint endPoint)
private void listen(ProxyEndPoint endPoint)
{
endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port);
try
......@@ -564,7 +626,7 @@ namespace Titanium.Web.Proxy
endPoint.Port = ((IPEndPoint)endPoint.Listener.LocalEndpoint).Port;
// accept clients asynchronously
endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint);
}
catch (SocketException ex)
{
......@@ -580,7 +642,7 @@ namespace Titanium.Web.Proxy
/// Verify if its safe to set this end point as system proxy.
/// </summary>
/// <param name="endPoint">The end point to validate.</param>
private void ValidateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint)
private void validateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint)
{
if (endPoint == null)
{
......@@ -603,7 +665,7 @@ namespace Titanium.Web.Proxy
/// </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);
return Task.FromResult(proxy);
......@@ -612,7 +674,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Act when a connection is received from client.
/// </summary>
private void OnAcceptConnection(IAsyncResult asyn)
private void onAcceptConnection(IAsyncResult asyn)
{
var endPoint = (ProxyEndPoint)asyn.AsyncState;
......@@ -637,11 +699,11 @@ namespace Titanium.Web.Proxy
if (tcpClient != null)
{
Task.Run(async () => { await HandleClient(tcpClient, endPoint); });
Task.Run(async () => { await handleClient(tcpClient, endPoint); });
}
// Get the listener that handles the client request.
endPoint.Listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint);
}
/// <summary>
......@@ -650,20 +712,24 @@ namespace Titanium.Web.Proxy
/// <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)
{
tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000;
tcpClient.SendBufferSize = BufferSize;
tcpClient.ReceiveBufferSize = BufferSize;
await InvokeConnectionCreateEvent(tcpClient, true);
using (var clientConnection = new TcpClientConnection(this, tcpClient))
{
if (endPoint is TransparentProxyEndPoint tep)
{
await HandleClient(tep, clientConnection);
await handleClient(tep, clientConnection);
}
else
{
await HandleClient((ExplicitProxyEndPoint)endPoint, clientConnection);
await handleClient((ExplicitProxyEndPoint)endPoint, clientConnection);
}
}
}
......@@ -673,7 +739,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <param name="exception">The exception.</param>
private void OnException(CustomBufferedStream clientStream, Exception exception)
private void onException(CustomBufferedStream clientStream, Exception exception)
{
#if DEBUG
if (clientStream is DebugCustomBufferedStream debugStream)
......@@ -688,7 +754,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Quit listening on the given end point.
/// </summary>
private void QuitListen(ProxyEndPoint endPoint)
private void quitListen(ProxyEndPoint endPoint)
{
endPoint.Listener.Stop();
endPoint.Listener.Server.Dispose();
......@@ -729,5 +795,34 @@ namespace Titanium.Web.Proxy
ServerConnectionCountChanged?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Invoke client/server tcp connection events if subscribed by API user.
/// </summary>
/// <param name="client">The TcpClient object.</param>
/// <param name="isClientConnection">Is this a client connection created event? If not then we would assume that its a server connection create event.</param>
/// <returns></returns>
internal async Task InvokeConnectionCreateEvent(TcpClient client, bool isClientConnection)
{
//client connection created
if (isClientConnection && OnClientConnectionCreate != null)
{
await OnClientConnectionCreate.InvokeAsync(this, client, ExceptionFunc);
}
//server connection created
if (!isClientConnection && OnServerConnectionCreate != null)
{
await OnServerConnectionCreate.InvokeAsync(this, client, ExceptionFunc);
}
}
/// <summary>
/// Connection retry policy when using connection pool.
/// </summary>
private RetryPolicy<T> retryPolicy<T>() where T : Exception
{
return new RetryPolicy<T>(retries, tcpConnectionFactory);
}
}
}
......@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
......@@ -25,7 +27,8 @@ namespace Titanium.Web.Proxy
private static readonly Regex uriSchemeRegex =
new Regex("^[a-z]*://", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly HashSet<string> proxySupportedCompressions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
private static readonly HashSet<string> proxySupportedCompressions =
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"gzip",
"deflate"
......@@ -49,15 +52,20 @@ namespace Titanium.Web.Proxy
/// explicit endpoint.
/// </param>
/// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param>
private async Task HandleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
/// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest)
CancellationTokenSource cancellationTokenSource, string httpsConnectHostname, ConnectRequest connectRequest,
Task<TcpServerConnection> prefetchConnectionTask = null)
{
var cancellationToken = cancellationTokenSource.Token;
TcpServerConnection serverConnection = null;
var prefetchTask = prefetchConnectionTask;
TcpServerConnection connection = null;
bool closeServerConnection = false;
try
{
var cancellationToken = cancellationTokenSource.Token;
// Loop through each subsequest request on this particular client connection
// (assuming HTTP connection is kept alive by client)
while (true)
......@@ -70,7 +78,7 @@ namespace Titanium.Web.Proxy
return;
}
var args = new SessionEventArgs(BufferSize, endPoint, cancellationTokenSource, ExceptionFunc)
var args = new SessionEventArgs(this, endPoint, cancellationTokenSource)
{
ProxyClient = { ClientConnection = clientConnection },
WebSession = { ConnectRequest = connectRequest }
......@@ -132,9 +140,9 @@ namespace Titanium.Web.Proxy
if (!args.IsTransparent)
{
// proxy authorization check
if (httpsConnectHostname == null && await CheckAuthorization(args) == false)
if (httpsConnectHostname == null && await checkAuthorization(args) == false)
{
await InvokeBeforeResponse(args);
await invokeBeforeResponse(args);
// send the response
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response,
......@@ -142,7 +150,7 @@ namespace Titanium.Web.Proxy
return;
}
PrepareRequestHeaders(request.Headers);
prepareRequestHeaders(request.Headers);
request.Host = request.RequestUri.Authority;
}
......@@ -154,10 +162,11 @@ namespace Titanium.Web.Proxy
await args.GetRequestBody(cancellationToken);
}
request.OriginalHasBody = request.HasBody;
//we need this to syphon out data from connection if API user changes them.
request.SetOriginalHeaders();
// If user requested interception do it
await InvokeBeforeRequest(args);
await invokeBeforeRequest(args);
var response = args.WebSession.Response;
......@@ -166,7 +175,7 @@ namespace Titanium.Web.Proxy
// syphon out the request body from client before setting the new body
await args.SyphonOutBodyAsync(true, cancellationToken);
await HandleHttpSessionResponse(args);
await handleHttpSessionResponse(args);
if (!response.KeepAlive)
{
......@@ -176,71 +185,75 @@ namespace Titanium.Web.Proxy
continue;
}
// create a new connection if hostname/upstream end point changes
if (serverConnection != null
&& (!serverConnection.HostName.EqualsIgnoreCase(request.RequestUri.Host)
|| args.WebSession.UpStreamEndPoint?.Equals(serverConnection.UpStreamEndPoint) ==
false))
//If prefetch task is available.
if (connection == null && prefetchTask != null)
{
serverConnection.Dispose();
serverConnection = null;
connection = await prefetchTask;
prefetchTask = null;
}
if (serverConnection == null)
// create a new connection if cache key changes.
// only gets hit when connection pool is disabled.
// or when prefetch task has a unexpectedly different connection.
if (connection != null
&& (await tcpConnectionFactory.GetConnectionCacheKey(this, args,
clientConnection.NegotiatedApplicationProtocol)
!= connection.CacheKey))
{
serverConnection = await GetServerConnection(args, false, clientConnection.NegotiatedApplicationProtocol, cancellationToken);
await tcpConnectionFactory.Release(connection);
connection = null;
}
// if upgrading to websocket then relay the requet without reading the contents
//a connection generator task with captured parameters via closure.
Func<Task<TcpServerConnection>> generator = () =>
tcpConnectionFactory.GetServerConnection(this, args, isConnect: false,
applicationProtocol:clientConnection.NegotiatedApplicationProtocol,
noCache: false, cancellationToken: cancellationToken);
//for connection pool, retry fails until cache is exhausted.
var result = await retryPolicy<ServerConnectionException>().ExecuteAsync(async (serverConnection) =>
{
// if upgrading to websocket then relay the request without reading the contents
if (request.UpgradeToWebSocket)
{
// prepare the prefix content
await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken);
string httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);
await handleWebSocketUpgrade(httpCmd, args, request,
response, clientStream, clientStreamWriter,
serverConnection, cancellationTokenSource, cancellationToken);
closeServerConnection = true;
return false;
}
Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode,
out string responseStatusDescription);
response.HttpVersion = responseVersion;
response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription;
// construct the web request that we are going to issue on behalf of the client.
await handleHttpSessionRequestInternal(serverConnection, args);
return true;
await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
cancellationToken);
}, generator, connection);
if (!args.IsTransparent)
{
await clientStreamWriter.WriteResponseAsync(response,
cancellationToken: cancellationToken);
}
//update connection to latest used
connection = result.LatestConnection;
// If user requested call back then do it
if (!args.WebSession.Response.Locked)
//throw if exception happened
if(!result.IsSuccess)
{
await InvokeBeforeResponse(args);
throw result.Exception;
}
await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
cancellationTokenSource, ExceptionFunc);
if(!result.Continue)
{
return;
}
// construct the web request that we are going to issue on behalf of the client.
await HandleHttpSessionRequestInternal(serverConnection, args);
if (args.WebSession.ServerConnection == null)
//user requested
if (args.WebSession.CloseServerConnection)
{
closeServerConnection = true;
return;
}
// if connection is closing exit
if (!response.KeepAlive)
{
closeServerConnection = true;
return;
}
......@@ -248,6 +261,19 @@ namespace Titanium.Web.Proxy
{
throw new Exception("Session was terminated by user.");
}
//Get/release server connection for each HTTP session instead of per client connection.
//This will be more efficient especially when client is idly holding server connection
//between sessions without using it.
//Do not release authenticated connections for performance reasons.
//Otherwise it will keep authenticating per session.
if (EnableConnectionPool && connection!=null
&& !connection.IsWinAuthenticated)
{
await tcpConnectionFactory.Release(connection);
connection = null;
}
}
catch (Exception e) when (!(e is ProxyHttpException))
{
......@@ -257,18 +283,22 @@ namespace Titanium.Web.Proxy
catch (Exception e)
{
args.Exception = e;
closeServerConnection = true;
throw;
}
finally
{
await InvokeAfterResponse(args);
await invokeAfterResponse(args);
args.Dispose();
}
}
}
finally
{
serverConnection?.Dispose();
await tcpConnectionFactory.Release(connection,
closeServerConnection);
await tcpConnectionFactory.Release(prefetchTask, closeServerConnection);
}
}
......@@ -278,9 +308,7 @@ namespace Titanium.Web.Proxy
/// <param name="serverConnection">The tcp connection.</param>
/// <param name="args">The session event arguments.</param>
/// <returns></returns>
private async Task HandleHttpSessionRequestInternal(TcpServerConnection serverConnection, SessionEventArgs args)
{
try
private async Task handleHttpSessionRequestInternal(TcpServerConnection serverConnection, SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
var request = args.WebSession.Request;
......@@ -348,72 +376,16 @@ namespace Titanium.Web.Proxy
// If not expectation failed response was returned by server then parse response
if (!request.ExpectationFailed)
{
await HandleHttpSessionResponse(args);
}
await handleHttpSessionResponse(args);
}
catch (Exception e) when (!(e is ProxyHttpException))
{
throw new ProxyHttpException("Error occured whilst handling session request (internal)", e, args);
}
}
/// <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="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>
/// <returns></returns>
private async Task<TcpServerConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect,
List<SslApplicationProtocol> applicationProtocols, CancellationToken cancellationToken)
{
ExternalProxy customUpStreamProxy = null;
bool isHttps = args.IsHttps;
if (GetCustomUpStreamProxyFunc != null)
{
customUpStreamProxy = await GetCustomUpStreamProxyFunc(args);
}
args.CustomUpStreamProxyUsed = customUpStreamProxy;
return await tcpConnectionFactory.CreateClient(
args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion,
isHttps, applicationProtocols, isConnect,
this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint,
customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy),
cancellationToken);
}
/// <summary>
/// Prepare the request headers so that we can avoid encodings not parsable by this proxy
/// </summary>
private void PrepareRequestHeaders(HeaderCollection requestHeaders)
private void prepareRequestHeaders(HeaderCollection requestHeaders)
{
var acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding);
string acceptEncoding = requestHeaders.GetHeaderValueOrNull(KnownHeaders.AcceptEncoding);
if (acceptEncoding != null)
{
......@@ -427,7 +399,8 @@ namespace Titanium.Web.Proxy
//uncompressed is always supported by proxy
supportedAcceptEncoding.Add("identity");
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, string.Join(",", supportedAcceptEncoding));
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding,
string.Join(",", supportedAcceptEncoding));
}
requestHeaders.FixProxyHeaders();
......@@ -438,7 +411,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <returns></returns>
private async Task InvokeBeforeRequest(SessionEventArgs args)
private async Task invokeBeforeRequest(SessionEventArgs args)
{
if (BeforeRequest != null)
{
......
using System;
using System.Net;
using System.Net;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Network.WinAuth.Security;
......@@ -14,13 +12,11 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer
{
/// <summary>
/// Called asynchronously when a request was successfully and we received the response.
/// Called asynchronously when a request was successfull and we received the response.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <returns> The task.</returns>
private async Task HandleHttpSessionResponse(SessionEventArgs args)
{
try
private async Task handleHttpSessionResponse(SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
......@@ -35,7 +31,7 @@ namespace Titanium.Web.Proxy
{
if (response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
await Handle401UnAuthorized(args);
await handle401UnAuthorized(args);
}
else
{
......@@ -43,12 +39,14 @@ namespace Titanium.Web.Proxy
}
}
response.OriginalHasBody = response.HasBody;
//save original values so that if user changes them
//we can still use original values when syphoning out data from attached tcp connection.
response.SetOriginalHeaders();
// if user requested call back then do it
if (!response.Locked)
{
await InvokeBeforeResponse(args);
await invokeBeforeResponse(args);
}
// it may changed in the user event
......@@ -56,20 +54,19 @@ namespace Titanium.Web.Proxy
var clientStreamWriter = args.ProxyClient.ClientStreamWriter;
if (response.TerminateResponse || response.Locked)
//user set custom response by ignoring original response from server.
if (response.Locked)
{
//write custom user response with body and return.
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
if (!response.TerminateResponse)
if(args.WebSession.ServerConnection != null
&& !args.WebSession.CloseServerConnection)
{
// syphon out the response body from server before setting the new body
// syphon out the original response body from server connection
// so that connection will be good to be reused.
await args.SyphonOutBodyAsync(false, cancellationToken);
}
else
{
args.WebSession.ServerConnection.Dispose();
args.WebSession.ServerConnection = null;
}
return;
}
......@@ -80,7 +77,7 @@ namespace Titanium.Web.Proxy
{
// clear current response
await args.ClearResponse(cancellationToken);
await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
await handleHttpSessionRequestInternal(args.WebSession.ServerConnection, args);
return;
}
......@@ -123,11 +120,7 @@ namespace Titanium.Web.Proxy
cancellationToken);
}
}
}
catch (Exception e) when (!(e is ProxyHttpException))
{
throw new ProxyHttpException("Error occured whilst handling session response", e, args);
}
}
/// <summary>
......@@ -135,7 +128,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private async Task InvokeBeforeResponse(SessionEventArgs args)
private async Task invokeBeforeResponse(SessionEventArgs args)
{
if (BeforeResponse != null)
{
......@@ -148,7 +141,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private async Task InvokeAfterResponse(SessionEventArgs args)
private async Task invokeAfterResponse(SessionEventArgs args)
{
if (AfterResponse != null)
{
......
......@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.2" />
<PackageReference Include="StreamExtended" Version="1.0.164" />
<PackageReference Include="StreamExtended" Version="1.0.179" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......@@ -34,8 +34,31 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<Compile Update="Network\WinAuth\Security\Common.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\LittleEndian.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\Message.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\State.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Properties\AssemblyInfo.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -14,7 +14,7 @@
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags>
<dependencies>
<dependency id="StreamExtended" version="1.0.164" />
<dependency id="StreamExtended" version="1.0.179" />
<dependency id="Portable.BouncyCastle" version="1.8.2" />
</dependencies>
</metadata>
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
......@@ -6,7 +7,6 @@ using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
......@@ -26,18 +26,21 @@ namespace Titanium.Web.Proxy
/// <param name="endPoint">The transparent endpoint.</param>
/// <param name="clientConnection">The client connection.</param>
/// <returns></returns>
private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection)
private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection)
{
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferSize);
var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
Task<TcpServerConnection> prefetchConnectionTask = null;
bool closeServerConnection = false;
bool calledRequestHandler = false;
try
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationToken);
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
bool isHttps = clientHelloInfo != null;
string httpsHostName = null;
......@@ -60,8 +63,16 @@ namespace Titanium.Web.Proxy
if (endPoint.DecryptSsl && args.DecryptSsl)
{
//don't pass cancellation token here
//it could cause floating server connections when client exits
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false,
proxyServer: this, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy,
noCache: false, cancellationToken: CancellationToken.None);
SslStream sslStream = null;
//do client authentication using fake certificate
try
{
sslStream = new SslStream(clientStream);
......@@ -73,9 +84,9 @@ namespace Titanium.Web.Proxy
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
// HTTPS server created - we can now decrypt the client's traffic
clientStream = new CustomBufferedStream(sslStream, BufferSize);
clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
}
catch (Exception e)
{
......@@ -86,26 +97,25 @@ namespace Titanium.Web.Proxy
}
else
{
// create new connection
var connection = new TcpClient(UpStreamEndPoint);
await connection.ConnectAsync(httpsHostName, endPoint.Port);
connection.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
connection.SendTimeout = ConnectionTimeOutSeconds * 1000;
var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
httpVersion: null, isHttps: false, applicationProtocols: null,
isConnect: true, proxyServer: this, upStreamEndPoint: UpStreamEndPoint,
externalProxy: UpStreamHttpsProxy, noCache: true, cancellationToken: cancellationToken);
using (connection)
try
{
var serverStream = connection.GetStream();
CustomBufferedStream serverStream = null;
int available = clientStream.Available;
if (available > 0)
{
// send the buffered data
var data = BufferPool.GetBuffer(BufferSize);
try
{
// clientStream.Available sbould be at most BufferSize because it is using the same buffer size
await clientStream.ReadAsync(data, 0, available, cancellationToken);
serverStream = connection.Stream;
await serverStream.WriteAsync(data, 0, available, cancellationToken);
await serverStream.FlushAsync(cancellationToken);
}
......@@ -115,38 +125,52 @@ namespace Titanium.Web.Proxy
}
}
////var serverHelloInfo = await SslTools.PeekServerHello(serverStream);
await TcpHelper.SendRaw(clientStream, serverStream, BufferSize,
await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize,
null, null, cancellationTokenSource, ExceptionFunc);
}
}
finally
{
await tcpConnectionFactory.Release(connection, true);
}
return;
}
}
calledRequestHandler = true;
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
await HandleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, isHttps ? httpsHostName : null, null);
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
cancellationTokenSource, isHttps ? httpsHostName : null, null, prefetchConnectionTask);
}
catch (ProxyException e)
{
OnException(clientStream, e);
closeServerConnection = true;
onException(clientStream, e);
}
catch (IOException e)
{
OnException(clientStream, new Exception("Connection was aborted", e));
closeServerConnection = true;
onException(clientStream, new Exception("Connection was aborted", e));
}
catch (SocketException e)
{
OnException(clientStream, new Exception("Could not connect", e));
closeServerConnection = true;
onException(clientStream, new Exception("Could not connect", e));
}
catch (Exception e)
{
OnException(clientStream, new Exception("Error occured in whilst handling the client", e));
closeServerConnection = true;
onException(clientStream, new Exception("Error occured in whilst handling the client", e));
}
finally
{
if (!calledRequestHandler)
{
await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
}
clientStream.Dispose();
if (!cancellationTokenSource.IsCancellationRequested)
{
cancellationTokenSource.Cancel();
......
using StreamExtended.Network;
using System;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy
{
public partial class ProxyServer
{
/// <summary>
/// Handle upgrade to websocket
/// </summary>
private async Task handleWebSocketUpgrade(string httpCmd,
SessionEventArgs args, Request request, Response response,
CustomBufferedStream clientStream, HttpResponseWriter clientStreamWriter,
TcpServerConnection serverConnection,
CancellationTokenSource cancellationTokenSource, CancellationToken cancellationToken)
{
// prepare the prefix content
await serverConnection.StreamWriter.WriteLineAsync(httpCmd, cancellationToken);
await serverConnection.StreamWriter.WriteHeadersAsync(request.Headers,
cancellationToken: cancellationToken);
string httpStatus;
try
{
httpStatus = await serverConnection.Stream.ReadLineAsync(cancellationToken);
if (httpStatus == null)
{
throw new ServerConnectionException("Server connection was closed.");
}
}
catch (Exception e) when (!(e is ServerConnectionException))
{
throw new ServerConnectionException("Server connection was closed.", e);
}
Response.ParseResponseLine(httpStatus, out var responseVersion,
out int responseStatusCode,
out string responseStatusDescription);
response.HttpVersion = responseVersion;
response.StatusCode = responseStatusCode;
response.StatusDescription = responseStatusDescription;
await HeaderParser.ReadHeaders(serverConnection.Stream, response.Headers,
cancellationToken);
if (!args.IsTransparent)
{
await clientStreamWriter.WriteResponseAsync(response,
cancellationToken: cancellationToken);
}
// If user requested call back then do it
if (!args.WebSession.Response.Locked)
{
await invokeBeforeResponse(args);
}
await TcpHelper.SendRaw(clientStream, serverConnection.Stream, BufferPool, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
cancellationTokenSource, ExceptionFunc);
}
}
}
......@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy
/// User to server to authenticate requests.
/// To disable this set ProxyServer.EnableWinAuth to false.
/// </summary>
internal async Task Handle401UnAuthorized(SessionEventArgs args)
private async Task handle401UnAuthorized(SessionEventArgs args)
{
string headerName = null;
HttpHeader authHeader = null;
......@@ -99,7 +99,7 @@ namespace Titanium.Web.Proxy
if (!WinAuthEndPoint.ValidateWinAuthState(args.WebSession.Data, expectedAuthState))
{
// Invalid state, create proper error message to client
await RewriteUnauthorizedResponse(args);
await rewriteUnauthorizedResponse(args);
return;
}
......@@ -145,6 +145,8 @@ namespace Titanium.Web.Proxy
{
request.ContentLength = request.Body.Length;
}
args.WebSession.ServerConnection.IsWinAuthenticated = true;
}
// Need to revisit this.
......@@ -161,7 +163,7 @@ namespace Titanium.Web.Proxy
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
internal async Task RewriteUnauthorizedResponse(SessionEventArgs args)
private async Task rewriteUnauthorizedResponse(SessionEventArgs args)
{
var response = args.WebSession.Response;
......
......@@ -2,5 +2,5 @@
<packages>
<package id="Portable.BouncyCastle" version="1.8.2" targetFramework="net45" />
<package id="StreamExtended" version="1.0.164" targetFramework="net45" />
<package id="StreamExtended" version="1.0.179" targetFramework="net45" />
</packages>
\ No newline at end of file
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Delegate AsyncEventHandler&lt;TEventArgs&gt;
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class BeforeSslAuthenticateEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateSelectionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateValidationEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class MultipartRequestPartSentEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -103,10 +103,13 @@ or when server terminates connection from proxy.</p>
<div class="inheritedMembers">
<h5>Inherited Members</h5>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_BufferSize">SessionEventArgsBase.BufferSize</a>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferSize">SessionEventArgsBase.bufferSize</a>
</div>
<div>
<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_bufferPool">SessionEventArgsBase.bufferPool</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_exceptionFunc">SessionEventArgsBase.exceptionFunc</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData">SessionEventArgsBase.UserData</a>
......@@ -177,12 +180,12 @@ or when server terminates connection from proxy.</p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_System_Int32_Titanium_Web_Proxy_Models_ProxyEndPoint_Titanium_Web_Proxy_Http_Request_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_ExceptionHandler_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.ExceptionHandler)">SessionEventArgs(Int32, ProxyEndPoint, Request, CancellationTokenSource, ExceptionHandler)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_Titanium_Web_Proxy_ProxyServer_Titanium_Web_Proxy_Models_ProxyEndPoint_Titanium_Web_Proxy_Http_Request_System_Threading_CancellationTokenSource_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource)">SessionEventArgs(ProxyServer, ProxyEndPoint, Request, CancellationTokenSource)</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">protected SessionEventArgs(int bufferSize, ProxyEndPoint endPoint, Request request, CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)</code></pre>
<pre><code class="lang-csharp hljs">protected SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, Request request, CancellationTokenSource cancellationTokenSource)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -195,8 +198,8 @@ or when server terminates connection from proxy.</p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td><span class="parametername">bufferSize</span></td>
<td><a class="xref" href="Titanium.Web.Proxy.ProxyServer.html">ProxyServer</a></td>
<td><span class="parametername">server</span></td>
<td></td>
</tr>
<tr>
......@@ -214,11 +217,6 @@ or when server terminates connection from proxy.</p>
<td><span class="parametername">cancellationTokenSource</span></td>
<td></td>
</tr>
<tr>
<td><a class="xref" href="Titanium.Web.Proxy.ExceptionHandler.html">ExceptionHandler</a></td>
<td><span class="parametername">exceptionFunc</span></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="properties">Properties
......@@ -267,14 +265,14 @@ or when server terminates connection from proxy.</p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_Byte___System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})">GenericResponse(Byte[], HttpStatusCode, Dictionary&lt;String, HttpHeader&gt;)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_Byte___System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)">GenericResponse(Byte[], HttpStatusCode, Dictionary&lt;String, HttpHeader&gt;, Boolean)</h4>
<div class="markdown level1 summary"><p>Before request is made to server respond with the specified byte[],
the specified status to client. And then ignore the request.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary&lt;string, HttpHeader&gt; headers)</code></pre>
<pre><code class="lang-csharp hljs">public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary&lt;string, HttpHeader&gt; headers, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -287,7 +285,7 @@ the specified status to client. And then ignore the request.</p>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">result</span></td>
<td><p>The bytes to sent.</p>
</td>
......@@ -302,6 +300,12 @@ the specified status to client. And then ignore the request.</p>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2">Dictionary</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;</td>
<td><span class="parametername">headers</span></td>
<td><p>The HTTP headers.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -309,7 +313,7 @@ the specified status to client. And then ignore the request.</p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_String_System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})">GenericResponse(String, HttpStatusCode, Dictionary&lt;String, HttpHeader&gt;)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_String_System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)">GenericResponse(String, HttpStatusCode, Dictionary&lt;String, HttpHeader&gt;, Boolean)</h4>
<div class="markdown level1 summary"><p>Before request is made to server
respond with the specified HTML string and the specified status to client.
And then ignore the request. </p>
......@@ -317,7 +321,7 @@ And then ignore the request. </p>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void GenericResponse(string html, HttpStatusCode status, Dictionary&lt;string, HttpHeader&gt; headers = null)</code></pre>
<pre><code class="lang-csharp hljs">public void GenericResponse(string html, HttpStatusCode status, Dictionary&lt;string, HttpHeader&gt; headers = null, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -345,6 +349,12 @@ And then ignore the request. </p>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2">Dictionary</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;</td>
<td><span class="parametername">headers</span></td>
<td><p>The HTTP headers.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -388,7 +398,7 @@ And then ignore the request. </p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<span class="xref">System.Byte</span>[]&gt;</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]&gt;</td>
<td><p>The body as bytes.</p>
</td>
</tr>
......@@ -478,7 +488,7 @@ And then ignore the request. </p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<span class="xref">System.Byte</span>[]&gt;</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]&gt;</td>
<td><p>The resulting bytes.</p>
</td>
</tr>
......@@ -532,14 +542,14 @@ And then ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_Byte___System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})">Ok(Byte[], Dictionary&lt;String, HttpHeader&gt;)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_Byte___System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)">Ok(Byte[], Dictionary&lt;String, HttpHeader&gt;, Boolean)</h4>
<div class="markdown level1 summary"><p>Before request is made to server respond with the specified byte[] to client
and ignore the request. </p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Ok(byte[] result, Dictionary&lt;string, HttpHeader&gt; headers = null)</code></pre>
<pre><code class="lang-csharp hljs">public void Ok(byte[] result, Dictionary&lt;string, HttpHeader&gt; headers = null, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -552,7 +562,7 @@ and ignore the request. </p>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">result</span></td>
<td><p>The html content bytes.</p>
</td>
......@@ -561,6 +571,12 @@ and ignore the request. </p>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2">Dictionary</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;</td>
<td><span class="parametername">headers</span></td>
<td><p>The HTTP headers.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -568,14 +584,14 @@ and ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_String_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})">Ok(String, Dictionary&lt;String, HttpHeader&gt;)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_String_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)">Ok(String, Dictionary&lt;String, HttpHeader&gt;, Boolean)</h4>
<div class="markdown level1 summary"><p>Before request is made to server respond with the specified HTML string to client
and ignore the request. </p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Ok(string html, Dictionary&lt;string, HttpHeader&gt; headers = null)</code></pre>
<pre><code class="lang-csharp hljs">public void Ok(string html, Dictionary&lt;string, HttpHeader&gt; headers = null, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -597,6 +613,12 @@ and ignore the request. </p>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2">Dictionary</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;</td>
<td><span class="parametername">headers</span></td>
<td><p>HTTP response headers.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -604,13 +626,13 @@ and ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_System_String_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String)">Redirect(String)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_System_String_System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String,System.Boolean)">Redirect(String, Boolean)</h4>
<div class="markdown level1 summary"><p>Redirect to provided URL.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Redirect(string url)</code></pre>
<pre><code class="lang-csharp hljs">public void Redirect(string url, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -626,6 +648,12 @@ and ignore the request. </p>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">url</span></td>
<td><p>The URL to redirect.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -633,13 +661,13 @@ and ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_Titanium_Web_Proxy_Http_Response_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response)">Respond(Response)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_Titanium_Web_Proxy_Http_Response_System_Boolean_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response,System.Boolean)">Respond(Response, Boolean)</h4>
<div class="markdown level1 summary"><p>Respond with given response object to client.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Respond(Response response)</code></pre>
<pre><code class="lang-csharp hljs">public void Respond(Response response, bool closeServerConnection = false)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -655,6 +683,12 @@ and ignore the request. </p>
<td><a class="xref" href="Titanium.Web.Proxy.Http.Response.html">Response</a></td>
<td><span class="parametername">response</span></td>
<td><p>The response object.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -681,7 +715,7 @@ and ignore the request. </p>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">body</span></td>
<td><p>The request body bytes.</p>
</td>
......@@ -739,7 +773,7 @@ and ignore the request. </p>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">body</span></td>
<td><p>The body bytes to set.</p>
</td>
......@@ -779,7 +813,7 @@ and ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_TerminateServerConnection_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.TerminateServerConnection*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_TerminateServerConnection" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.TerminateServerConnection">TerminateServerConnection()</h4>
<div class="markdown level1 summary"><p>Terminate the connection to server.</p>
<div class="markdown level1 summary"><p>Terminate the connection to server at the end of this HTTP request/response session.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class SessionEventArgsBase
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -139,12 +139,12 @@ or when server terminates connection from proxy.</p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_System_Int32_Titanium_Web_Proxy_Models_ProxyEndPoint_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_Http_Request_Titanium_Web_Proxy_ExceptionHandler_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request,Titanium.Web.Proxy.ExceptionHandler)">SessionEventArgsBase(Int32, ProxyEndPoint, CancellationTokenSource, Request, ExceptionHandler)</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_Titanium_Web_Proxy_ProxyServer_Titanium_Web_Proxy_Models_ProxyEndPoint_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_Http_Request_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request)">SessionEventArgsBase(ProxyServer, ProxyEndPoint, CancellationTokenSource, Request)</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, CancellationTokenSource cancellationTokenSource, Request request, ExceptionHandler exceptionFunc)</code></pre>
<pre><code class="lang-csharp hljs">protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint, CancellationTokenSource cancellationTokenSource, Request request)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -157,8 +157,8 @@ or when server terminates connection from proxy.</p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td><span class="parametername">bufferSize</span></td>
<td><a class="xref" href="Titanium.Web.Proxy.ProxyServer.html">ProxyServer</a></td>
<td><span class="parametername">server</span></td>
<td></td>
</tr>
<tr>
......@@ -176,24 +176,42 @@ or when server terminates connection from proxy.</p>
<td><span class="parametername">request</span></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="fields">Fields
</h3>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferPool" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferPool">bufferPool</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">protected readonly IBufferPool bufferPool</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="Titanium.Web.Proxy.ExceptionHandler.html">ExceptionHandler</a></td>
<td><span class="parametername">exceptionFunc</span></td>
<td><span class="xref">StreamExtended.IBufferPool</span></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="fields">Fields
</h3>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_BufferSize" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.BufferSize">BufferSize</h4>
<div class="markdown level1 summary"><p>Size of Buffers used by this object</p>
</div>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferSize" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferSize">bufferSize</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">protected readonly int BufferSize</code></pre>
<pre><code class="lang-csharp hljs">protected readonly int bufferSize</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -212,12 +230,12 @@ or when server terminates connection from proxy.</p>
</table>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc">ExceptionFunc</h4>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_exceptionFunc" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.exceptionFunc">exceptionFunc</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">protected readonly ExceptionHandler ExceptionFunc</code></pre>
<pre><code class="lang-csharp hljs">protected readonly ExceptionHandler exceptionFunc</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class TunnelConnectSessionEventArgs
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -100,10 +100,13 @@
<div class="inheritedMembers">
<h5>Inherited Members</h5>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_BufferSize">SessionEventArgsBase.BufferSize</a>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferSize">SessionEventArgsBase.bufferSize</a>
</div>
<div>
<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_bufferPool">SessionEventArgsBase.bufferPool</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_exceptionFunc">SessionEventArgsBase.exceptionFunc</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_UserData">SessionEventArgsBase.UserData</a>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.EventArguments
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Delegate ExceptionHandler
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class BodyNotFoundException
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyAuthorizationException
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyException
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyHttpException
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Exceptions
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ConnectRequest
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -136,6 +136,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ConnectResponse
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -118,6 +118,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class HeaderCollection
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -278,7 +278,7 @@ public class HeaderCollection : IEnumerable&lt;HttpHeader&gt;, IEnumerable</code
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a>&lt;<span class="xref">System.Collections.Generic.KeyValuePair</span>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>&gt;&gt;</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.keyvaluepair-2">KeyValuePair</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>&gt;&gt;</td>
<td><span class="parametername">newHeaders</span></td>
<td></td>
</tr>
......@@ -306,7 +306,7 @@ public class HeaderCollection : IEnumerable&lt;HttpHeader&gt;, IEnumerable</code
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a>&lt;<span class="xref">System.Collections.Generic.KeyValuePair</span>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;&gt;</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.keyvaluepair-2">KeyValuePair</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="Titanium.Web.Proxy.Models.HttpHeader.html">HttpHeader</a>&gt;&gt;</td>
<td><span class="parametername">newHeaders</span></td>
<td></td>
</tr>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class HttpWebClient
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class KnownHeaders
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class Request
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -98,6 +98,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class RequestResponseBase
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -143,7 +143,7 @@ public byte[] Body { get; }</code></pre>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td></td>
</tr>
</tbody>
......@@ -169,7 +169,7 @@ public byte[] Body { get; }</code></pre>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td></td>
</tr>
</tbody>
......@@ -488,6 +488,33 @@ public string BodyString { get; }</code></pre>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead_" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead*"></a>
<h4 id="Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead" data-uid="Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead">OriginalIsBodyRead</h4>
<div class="markdown level1 summary"><p>Store whether the original request/response body was read by user.
We need this detail to syphon out attached tcp connection for reuse.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool OriginalIsBodyRead { get; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="methods">Methods
</h3>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class Response
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -101,6 +101,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......@@ -198,7 +201,7 @@ public class Response : RequestResponseBase</code></pre>
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">body</span></td>
<td></td>
</tr>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class GenericResponse
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -119,6 +119,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class OkResponse
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -119,6 +119,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......@@ -215,7 +218,7 @@
</thead>
<tbody>
<tr>
<td><span class="xref">System.Byte</span>[]</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.byte">Byte</a>[]</td>
<td><span class="parametername">body</span></td>
<td></td>
</tr>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class RedirectResponse
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -119,6 +119,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_BodyInternal">RequestResponseBase.BodyInternal</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead">RequestResponseBase.OriginalIsBodyRead</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_KeepBody">RequestResponseBase.KeepBody</a>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Http.Responses
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Http
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ExplicitProxyEndPoint
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ExternalProxy
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class HttpHeader
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -155,6 +155,35 @@
</tr>
</tbody>
</table>
<h3 id="fields">Fields
</h3>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_HttpHeaderOverhead" data-uid="Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead">HttpHeaderOverhead</h4>
<div class="markdown level1 summary"><p>HPACK: Header Compression for HTTP/2
Section 4.1. Calculating Table Size
The additional 32 octets account for an estimated overhead associated with an entry. </p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const int HttpHeaderOverhead = 32</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="properties">Properties
</h3>
......@@ -185,6 +214,31 @@
</table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_Size_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Size*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_Size" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Size">Size</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public int Size { get; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_Value_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_Value" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value">Value</h4>
<div class="markdown level1 summary"><p>Header Value.</p>
......@@ -213,6 +267,53 @@
</h3>
<a id="Titanium_Web_Proxy_Models_HttpHeader_SizeOf_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.SizeOf*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_SizeOf_System_String_System_String_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)">SizeOf(String, String)</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static int SizeOf(string name, string value)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">name</span></td>
<td></td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">value</span></td>
<td></td>
</tr>
</tbody>
</table>
<h5 class="returns">Returns</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_ToString_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_ToString" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString">ToString()</h4>
<div class="markdown level1 summary"><p>Returns header as a valid header string.</p>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyEndPoint
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class TransparentProxyEndPoint
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Models
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Enum CertificateEngine
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class CertificateManager
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy.Network
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Class ProxyServer
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......@@ -230,16 +230,16 @@ prompting for UAC if required?</p>
</h3>
<a id="Titanium_Web_Proxy_ProxyServer_AuthenticateUserFunc_" data-uid="Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc*"></a>
<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.
Parameters are username and password as provided by client.
Should return true for successful authentication.</p>
<a id="Titanium_Web_Proxy_ProxyServer_BufferPool_" data-uid="Titanium.Web.Proxy.ProxyServer.BufferPool*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_BufferPool" data-uid="Titanium.Web.Proxy.ProxyServer.BufferPool">BufferPool</h4>
<div class="markdown level1 summary"><p>The buffer pool used throughout this proxy instance.
Set custom implementations by implementing this interface.
By default this uses DefaultBufferPool implementation available in StreamExtended library package.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public Func&lt;string, string, Task&lt;bool&gt;&gt; AuthenticateUserFunc { get; set; }</code></pre>
<pre><code class="lang-csharp hljs">public IBufferPool BufferPool { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -251,7 +251,7 @@ Should return true for successful authentication.</p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.func-3">Func</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a>&gt;&gt;</td>
<td><span class="xref">StreamExtended.IBufferPool</span></td>
<td></td>
</tr>
</tbody>
......@@ -260,7 +260,8 @@ Should return true for successful authentication.</p>
<a id="Titanium_Web_Proxy_ProxyServer_BufferSize_" data-uid="Titanium.Web.Proxy.ProxyServer.BufferSize*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_BufferSize" data-uid="Titanium.Web.Proxy.ProxyServer.BufferSize">BufferSize</h4>
<div class="markdown level1 summary"><p>Buffer size used throughout this proxy.</p>
<div class="markdown level1 summary"><p>Buffer size in bytes used throughout this proxy.
Default value is 8192 bytes.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......@@ -365,7 +366,9 @@ Note: If enabled can reduce performance. Defaults to false.</p>
<a id="Titanium_Web_Proxy_ProxyServer_ConnectionTimeOutSeconds_" data-uid="Titanium.Web.Proxy.ProxyServer.ConnectionTimeOutSeconds*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ConnectionTimeOutSeconds" data-uid="Titanium.Web.Proxy.ProxyServer.ConnectionTimeOutSeconds">ConnectionTimeOutSeconds</h4>
<div class="markdown level1 summary"><p>Seconds client/server connection are to be kept alive when waiting for read/write to complete.</p>
<div class="markdown level1 summary"><p>Seconds client/server connection are to be kept alive when waiting for read/write to complete.
This will also determine the pool eviction time when connection pool is enabled.
Default value is 60 seconds.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......@@ -417,12 +420,40 @@ Defaults to false.</p>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_EnableConnectionPool_" data-uid="Titanium.Web.Proxy.ProxyServer.EnableConnectionPool*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_EnableConnectionPool" data-uid="Titanium.Web.Proxy.ProxyServer.EnableConnectionPool">EnableConnectionPool</h4>
<div class="markdown level1 summary"><p>Should we enable experimental server connection pool?
Defaults to disable.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool EnableConnectionPool { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td></td>
</tr>
</tbody>
</table>
<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>
<div class="markdown level1 summary"><p>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.</p>
in middle attack with Windows domain authentication is not currently supported.
Defaults to false.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......@@ -474,7 +505,8 @@ in middle attack with Windows domain authentication is not currently supported.<
<a id="Titanium_Web_Proxy_ProxyServer_ForwardToUpstreamGateway_" data-uid="Titanium.Web.Proxy.ProxyServer.ForwardToUpstreamGateway*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ForwardToUpstreamGateway" data-uid="Titanium.Web.Proxy.ProxyServer.ForwardToUpstreamGateway">ForwardToUpstreamGateway</h4>
<div class="markdown level1 summary"><p>Gets or sets a value indicating whether requests will be chained to upstream gateway.</p>
<div class="markdown level1 summary"><p>Gets or sets a value indicating whether requests will be chained to upstream gateway.
Defaults to false.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......@@ -525,14 +557,16 @@ User should return the ExternalProxy object with valid credentials.</p>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyEndPoints_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyEndPoints*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyEndPoints" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyEndPoints">ProxyEndPoints</h4>
<div class="markdown level1 summary"><p>A list of IpAddress and port this proxy is listening to.</p>
<a id="Titanium_Web_Proxy_ProxyServer_MaxCachedConnections_" data-uid="Titanium.Web.Proxy.ProxyServer.MaxCachedConnections*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_MaxCachedConnections" data-uid="Titanium.Web.Proxy.ProxyServer.MaxCachedConnections">MaxCachedConnections</h4>
<div class="markdown level1 summary"><p>Maximum number of concurrent connections per remote host in cache.
Only valid when connection pooling is enabled.
Default value is 2.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public List&lt;ProxyEndPoint&gt; ProxyEndPoints { get; set; }</code></pre>
<pre><code class="lang-csharp hljs">public int MaxCachedConnections { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -544,21 +578,21 @@ User should return the ExternalProxy object with valid credentials.</p>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.list-1">List</a>&lt;<a class="xref" href="Titanium.Web.Proxy.Models.ProxyEndPoint.html">ProxyEndPoint</a>&gt;</td>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyRealm_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyRealm*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyRealm" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyRealm">ProxyRealm</h4>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationRealm_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationRealm" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm">ProxyAuthenticationRealm</h4>
<div class="markdown level1 summary"><p>Realm used during Proxy Basic Authentication.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public string ProxyRealm { get; set; }</code></pre>
<pre><code class="lang-csharp hljs">public string ProxyAuthenticationRealm { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -577,6 +611,87 @@ User should return the ExternalProxy object with valid credentials.</p>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationSchemes_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationSchemes" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes">ProxyAuthenticationSchemes</h4>
<div class="markdown level1 summary"><p>A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required.
Works in relation with ProxySchemeAuthenticateFunc.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public IEnumerable&lt;string&gt; ProxyAuthenticationSchemes { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyBasicAuthenticateFunc_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyBasicAuthenticateFunc" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc">ProxyBasicAuthenticateFunc</h4>
<div class="markdown level1 summary"><p>A callback to authenticate proxy clients via basic authentication.
Parameters are username and password as provided by client.
Should return true for successful authentication.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public Func&lt;SessionEventArgsBase, string, string, Task&lt;bool&gt;&gt; ProxyBasicAuthenticateFunc { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.func-4">Func</a>&lt;<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html">SessionEventArgsBase</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a>&gt;&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyEndPoints_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyEndPoints*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyEndPoints" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyEndPoints">ProxyEndPoints</h4>
<div class="markdown level1 summary"><p>A list of IpAddress and port this proxy is listening to.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public List&lt;ProxyEndPoint&gt; ProxyEndPoints { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.collections.generic.list-1">List</a>&lt;<a class="xref" href="Titanium.Web.Proxy.Models.ProxyEndPoint.html">ProxyEndPoint</a>&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxyRunning_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyRunning*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxyRunning" data-uid="Titanium.Web.Proxy.ProxyServer.ProxyRunning">ProxyRunning</h4>
<div class="markdown level1 summary"><p>Is the proxy currently running?</p>
......@@ -603,6 +718,34 @@ User should return the ExternalProxy object with valid credentials.</p>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ProxySchemeAuthenticateFunc_" data-uid="Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ProxySchemeAuthenticateFunc" data-uid="Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc">ProxySchemeAuthenticateFunc</h4>
<div class="markdown level1 summary"><p>A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc.
Parameters are current working session, schemeType, and token as provided by a calling client.
Should return success for successful authentication, continuation if the package requests, or failure.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public Func&lt;SessionEventArgsBase, string, string, Task&lt;ProxyAuthenticationContext&gt;&gt; ProxySchemeAuthenticateFunc { get; set; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.func-4">Func</a>&lt;<a class="xref" href="Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html">SessionEventArgsBase</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a>, <a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<span class="xref">ProxyAuthenticationContext</span>&gt;&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_ProxyServer_ServerConnectionCount_" data-uid="Titanium.Web.Proxy.ProxyServer.ServerConnectionCount*"></a>
<h4 id="Titanium_Web_Proxy_ProxyServer_ServerConnectionCount" data-uid="Titanium.Web.Proxy.ProxyServer.ServerConnectionCount">ServerConnectionCount</h4>
<div class="markdown level1 summary"><p>Total number of active server connections.</p>
......@@ -1109,6 +1252,56 @@ Will throw error if the end point does&apos;nt exist.</p>
</table>
<h4 id="Titanium_Web_Proxy_ProxyServer_OnClientConnectionCreate" data-uid="Titanium.Web.Proxy.ProxyServer.OnClientConnectionCreate">OnClientConnectionCreate</h4>
<div class="markdown level1 summary"><p>Customize TcpClient used for client connection upon create.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public event AsyncEventHandler&lt;TcpClient&gt; OnClientConnectionCreate</code></pre>
</div>
<h5 class="eventType">Event Type</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html">AsyncEventHandler</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.net.sockets.tcpclient">TcpClient</a>&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="Titanium_Web_Proxy_ProxyServer_OnServerConnectionCreate" data-uid="Titanium.Web.Proxy.ProxyServer.OnServerConnectionCreate">OnServerConnectionCreate</h4>
<div class="markdown level1 summary"><p>Customize TcpClient used for server connection upon create.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public event AsyncEventHandler&lt;TcpClient&gt; OnServerConnectionCreate</code></pre>
</div>
<h5 class="eventType">Event Type</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html">AsyncEventHandler</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.net.sockets.tcpclient">TcpClient</a>&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<h4 id="Titanium_Web_Proxy_ProxyServer_ServerCertificateValidationCallback" data-uid="Titanium.Web.Proxy.ProxyServer.ServerCertificateValidationCallback">ServerCertificateValidationCallback</h4>
<div class="markdown level1 summary"><p>Event to override the default verification logic of remote SSL certificate received during authentication.</p>
</div>
......
......@@ -10,7 +10,7 @@
<meta name="viewport" content="width=device-width">
<meta name="title" content="Namespace Titanium.Web.Proxy
| Titanium Web Proxy ">
<meta name="generator" content="docfx 2.35.4.0">
<meta name="generator" content="docfx 2.37.0.0">
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="../styles/docfx.vendor.css">
......
......@@ -32,17 +32,17 @@
"api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html": {
"href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html",
"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.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"
"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.bufferPool 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(ProxyServer, ProxyEndPoint, Request, CancellationTokenSource) Declaration protected SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, Request request, CancellationTokenSource cancellationTokenSource) Parameters Type Name Description ProxyServer server ProxyEndPoint endPoint Request request CancellationTokenSource cancellationTokenSource 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>, Boolean) 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, bool closeServerConnection = false) Parameters Type Name Description Byte [] result The bytes to sent. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. Boolean closeServerConnection Close the server connection used by request if any? GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>, Boolean) 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, bool closeServerConnection = false) Parameters Type Name Description String html The html content. HttpStatusCode status The HTTP status code. Dictionary < String , HttpHeader > headers The HTTP headers. Boolean closeServerConnection Close the server connection used by request if any? 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 < 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 < 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>, Boolean) 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, bool closeServerConnection = false) Parameters Type Name Description Byte [] result The html content bytes. Dictionary < String , HttpHeader > headers The HTTP headers. Boolean closeServerConnection Close the server connection used by request if any? Ok(String, Dictionary<String, HttpHeader>, Boolean) 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, bool closeServerConnection = false) Parameters Type Name Description String html HTML content to sent. Dictionary < String , HttpHeader > headers HTTP response headers. Boolean closeServerConnection Close the server connection used by request if any? Redirect(String, Boolean) Redirect to provided URL. Declaration public void Redirect(string url, bool closeServerConnection = false) Parameters Type Name Description String url The URL to redirect. Boolean closeServerConnection Close the server connection used by request if any? Respond(Response, Boolean) Respond with given response object to client. Declaration public void Respond(Response response, bool closeServerConnection = false) Parameters Type Name Description Response response The response object. Boolean closeServerConnection Close the server connection used by request if any? SetRequestBody(Byte[]) Sets the request body. Declaration public void SetRequestBody(byte[] body) Parameters Type Name Description 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 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 at the end of this HTTP request/response session. 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": {
"href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html",
"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 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"
"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(ProxyServer, ProxyEndPoint, CancellationTokenSource, Request) Declaration protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint, CancellationTokenSource cancellationTokenSource, Request request) Parameters Type Name Description ProxyServer server ProxyEndPoint endPoint CancellationTokenSource cancellationTokenSource Request request Fields bufferPool Declaration protected readonly IBufferPool bufferPool Field Value Type Description StreamExtended.IBufferPool bufferSize 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": {
"href": "api/Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html",
"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.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"
"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.bufferPool 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": {
"href": "api/Titanium.Web.Proxy.ExceptionHandler.html",
......@@ -82,17 +82,17 @@
"api/Titanium.Web.Proxy.Http.ConnectRequest.html": {
"href": "api/Titanium.Web.Proxy.Http.ConnectRequest.html",
"title": "Class ConnectRequest | Titanium Web Proxy",
"keywords": "Class ConnectRequest Inheritance Object RequestResponseBase Request ConnectRequest Inherited Members Request.Method Request.RequestUri Request.IsHttps Request.OriginalUrl Request.HasBody Request.Host Request.ExpectContinue Request.IsMultipartFormData Request.Url Request.UpgradeToWebSocket Request.Is100Continue Request.ExpectationFailed Request.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 Assembly : Titanium.Web.Proxy.dll Syntax public class ConnectRequest : Request Constructors ConnectRequest() Declaration public ConnectRequest() Properties ClientHelloInfo Declaration public ClientHelloInfo ClientHelloInfo { get; set; } Property Value Type Description StreamExtended.ClientHelloInfo"
"keywords": "Class ConnectRequest Inheritance Object RequestResponseBase Request ConnectRequest Inherited Members Request.Method Request.RequestUri Request.IsHttps Request.OriginalUrl Request.HasBody Request.Host Request.ExpectContinue Request.IsMultipartFormData Request.Url Request.UpgradeToWebSocket Request.Is100Continue Request.ExpectationFailed Request.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 Assembly : Titanium.Web.Proxy.dll Syntax public class ConnectRequest : Request Constructors ConnectRequest() Declaration public ConnectRequest() Properties ClientHelloInfo Declaration public ClientHelloInfo ClientHelloInfo { get; set; } Property Value Type Description StreamExtended.ClientHelloInfo"
},
"api/Titanium.Web.Proxy.Http.ConnectResponse.html": {
"href": "api/Titanium.Web.Proxy.Http.ConnectResponse.html",
"title": "Class ConnectResponse | Titanium Web Proxy",
"keywords": "Class ConnectResponse Inheritance Object RequestResponseBase Response ConnectResponse 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 Assembly : Titanium.Web.Proxy.dll Syntax public class ConnectResponse : Response Properties ServerHelloInfo Declaration public ServerHelloInfo ServerHelloInfo { get; set; } Property Value Type Description StreamExtended.ServerHelloInfo"
"keywords": "Class ConnectResponse Inheritance Object RequestResponseBase Response ConnectResponse Inherited Members Response.StatusCode Response.StatusDescription Response.HasBody Response.KeepAlive Response.Is100Continue Response.ExpectationFailed Response.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 Assembly : Titanium.Web.Proxy.dll Syntax public class ConnectResponse : Response Properties ServerHelloInfo Declaration public ServerHelloInfo ServerHelloInfo { get; set; } Property Value Type Description StreamExtended.ServerHelloInfo"
},
"api/Titanium.Web.Proxy.Http.HeaderCollection.html": {
"href": "api/Titanium.Web.Proxy.Http.HeaderCollection.html",
"title": "Class HeaderCollection | Titanium Web Proxy",
"keywords": "Class HeaderCollection Inheritance Object HeaderCollection Implements IEnumerable < HttpHeader > IEnumerable 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 [TypeConverter(typeof(ExpandableObjectConverter))] public class HeaderCollection : IEnumerable<HttpHeader>, IEnumerable Constructors HeaderCollection() Initializes a new instance of the HeaderCollection class. Declaration public HeaderCollection() Properties Headers Unique Request header collection. Declaration public ReadOnlyDictionary<string, HttpHeader> Headers { get; } Property Value Type Description ReadOnlyDictionary < String , HttpHeader > NonUniqueHeaders Non Unique headers. Declaration public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; } Property Value Type Description ReadOnlyDictionary < String , List < HttpHeader >> Methods AddHeader(String, String) Add a new header with given name and value Declaration public void AddHeader(string name, string value) Parameters Type Name Description String name String value AddHeader(HttpHeader) Adds the given header object to Request Declaration public void AddHeader(HttpHeader newHeader) Parameters Type Name Description HttpHeader newHeader AddHeaders(IEnumerable<KeyValuePair<String, String>>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<KeyValuePair<string, string>> newHeaders) Parameters Type Name Description IEnumerable < System.Collections.Generic.KeyValuePair < String , String >> newHeaders AddHeaders(IEnumerable<KeyValuePair<String, HttpHeader>>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>> newHeaders) Parameters Type Name Description IEnumerable < System.Collections.Generic.KeyValuePair < String , HttpHeader >> newHeaders AddHeaders(IEnumerable<HttpHeader>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<HttpHeader> newHeaders) Parameters Type Name Description IEnumerable < HttpHeader > newHeaders Clear() Removes all the headers. Declaration public void Clear() GetAllHeaders() Returns all headers Declaration public List<HttpHeader> GetAllHeaders() Returns Type Description List < HttpHeader > GetEnumerator() Returns an enumerator that iterates through the collection. Declaration public IEnumerator<HttpHeader> GetEnumerator() Returns Type Description IEnumerator < HttpHeader > An enumerator that can be used to iterate through the collection. GetFirstHeader(String) Declaration public HttpHeader GetFirstHeader(string name) Parameters Type Name Description String name Returns Type Description HttpHeader GetHeaders(String) Returns all headers with given name if exists Returns null if does'nt exist Declaration public List<HttpHeader> GetHeaders(string name) Parameters Type Name Description String name Returns Type Description List < HttpHeader > HeaderExists(String) True if header exists Declaration public bool HeaderExists(string name) Parameters Type Name Description String name Returns Type Description Boolean RemoveHeader(String) removes all headers with given name Declaration public bool RemoveHeader(string headerName) Parameters Type Name Description String headerName Returns Type Description Boolean True if header was removed False if no header exists with given name RemoveHeader(HttpHeader) Removes given header object if it exist Declaration public bool RemoveHeader(HttpHeader header) Parameters Type Name Description HttpHeader header Returns true if header exists and was removed Returns Type Description Boolean Explicit Interface Implementations IEnumerable.GetEnumerator() Declaration IEnumerator IEnumerable.GetEnumerator() Returns Type Description IEnumerator Implements System.Collections.Generic.IEnumerable<T> System.Collections.IEnumerable"
"keywords": "Class HeaderCollection Inheritance Object HeaderCollection Implements IEnumerable < HttpHeader > IEnumerable 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 [TypeConverter(typeof(ExpandableObjectConverter))] public class HeaderCollection : IEnumerable<HttpHeader>, IEnumerable Constructors HeaderCollection() Initializes a new instance of the HeaderCollection class. Declaration public HeaderCollection() Properties Headers Unique Request header collection. Declaration public ReadOnlyDictionary<string, HttpHeader> Headers { get; } Property Value Type Description ReadOnlyDictionary < String , HttpHeader > NonUniqueHeaders Non Unique headers. Declaration public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; } Property Value Type Description ReadOnlyDictionary < String , List < HttpHeader >> Methods AddHeader(String, String) Add a new header with given name and value Declaration public void AddHeader(string name, string value) Parameters Type Name Description String name String value AddHeader(HttpHeader) Adds the given header object to Request Declaration public void AddHeader(HttpHeader newHeader) Parameters Type Name Description HttpHeader newHeader AddHeaders(IEnumerable<KeyValuePair<String, String>>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<KeyValuePair<string, string>> newHeaders) Parameters Type Name Description IEnumerable < KeyValuePair < String , String >> newHeaders AddHeaders(IEnumerable<KeyValuePair<String, HttpHeader>>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<KeyValuePair<string, HttpHeader>> newHeaders) Parameters Type Name Description IEnumerable < KeyValuePair < String , HttpHeader >> newHeaders AddHeaders(IEnumerable<HttpHeader>) Adds the given header objects to Request Declaration public void AddHeaders(IEnumerable<HttpHeader> newHeaders) Parameters Type Name Description IEnumerable < HttpHeader > newHeaders Clear() Removes all the headers. Declaration public void Clear() GetAllHeaders() Returns all headers Declaration public List<HttpHeader> GetAllHeaders() Returns Type Description List < HttpHeader > GetEnumerator() Returns an enumerator that iterates through the collection. Declaration public IEnumerator<HttpHeader> GetEnumerator() Returns Type Description IEnumerator < HttpHeader > An enumerator that can be used to iterate through the collection. GetFirstHeader(String) Declaration public HttpHeader GetFirstHeader(string name) Parameters Type Name Description String name Returns Type Description HttpHeader GetHeaders(String) Returns all headers with given name if exists Returns null if does'nt exist Declaration public List<HttpHeader> GetHeaders(string name) Parameters Type Name Description String name Returns Type Description List < HttpHeader > HeaderExists(String) True if header exists Declaration public bool HeaderExists(string name) Parameters Type Name Description String name Returns Type Description Boolean RemoveHeader(String) removes all headers with given name Declaration public bool RemoveHeader(string headerName) Parameters Type Name Description String headerName Returns Type Description Boolean True if header was removed False if no header exists with given name RemoveHeader(HttpHeader) Removes given header object if it exist Declaration public bool RemoveHeader(HttpHeader header) Parameters Type Name Description HttpHeader header Returns true if header exists and was removed Returns Type Description Boolean Explicit Interface Implementations IEnumerable.GetEnumerator() Declaration IEnumerator IEnumerable.GetEnumerator() Returns Type Description IEnumerator Implements System.Collections.Generic.IEnumerable<T> System.Collections.IEnumerable"
},
"api/Titanium.Web.Proxy.Http.html": {
"href": "api/Titanium.Web.Proxy.Http.html",
......@@ -112,22 +112,22 @@
"api/Titanium.Web.Proxy.Http.Request.html": {
"href": "api/Titanium.Web.Proxy.Http.Request.html",
"title": "Class Request | Titanium Web Proxy",
"keywords": "Class Request Http(s) request object Inheritance Object RequestResponseBase Request ConnectRequest Inherited Members 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 Assembly : Titanium.Web.Proxy.dll Syntax [TypeConverter(typeof(ExpandableObjectConverter))] public class Request : RequestResponseBase Properties ExpectationFailed Did server responsed negatively for the request for 100 continue? Declaration public bool ExpectationFailed { get; } Property Value Type Description Boolean ExpectContinue Does this request has a 100-continue header? Declaration public bool ExpectContinue { get; } Property Value Type Description Boolean HasBody Has request body? Declaration public override bool HasBody { get; } Property Value Type Description Boolean Overrides RequestResponseBase.HasBody HeaderText Gets the header text. Declaration public override string HeaderText { get; } Property Value Type Description String Overrides RequestResponseBase.HeaderText Host Http hostname header value if exists. Note: Changing this does NOT change host in RequestUri. Users can set new RequestUri separately. Declaration public string Host { get; set; } Property Value Type Description String Is100Continue Did server responsed positively for 100 continue request? Declaration public bool Is100Continue { get; } Property Value Type Description Boolean IsHttps Is Https? Declaration public bool IsHttps { get; } Property Value Type Description Boolean IsMultipartFormData Does this request contain multipart/form-data? Declaration public bool IsMultipartFormData { get; } Property Value Type Description Boolean Method Request Method. Declaration public string Method { get; set; } Property Value Type Description String OriginalUrl The original request Url. Declaration public string OriginalUrl { get; set; } Property Value Type Description String RequestUri Request HTTP Uri. Declaration public Uri RequestUri { get; set; } Property Value Type Description Uri UpgradeToWebSocket Does this request has an upgrade to websocket header? Declaration public bool UpgradeToWebSocket { get; } Property Value Type Description Boolean Url Request Url. Declaration public string Url { get; } Property Value Type Description String"
"keywords": "Class Request Http(s) request object Inheritance Object RequestResponseBase Request ConnectRequest Inherited Members RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 Assembly : Titanium.Web.Proxy.dll Syntax [TypeConverter(typeof(ExpandableObjectConverter))] public class Request : RequestResponseBase Properties ExpectationFailed Did server responsed negatively for the request for 100 continue? Declaration public bool ExpectationFailed { get; } Property Value Type Description Boolean ExpectContinue Does this request has a 100-continue header? Declaration public bool ExpectContinue { get; } Property Value Type Description Boolean HasBody Has request body? Declaration public override bool HasBody { get; } Property Value Type Description Boolean Overrides RequestResponseBase.HasBody HeaderText Gets the header text. Declaration public override string HeaderText { get; } Property Value Type Description String Overrides RequestResponseBase.HeaderText Host Http hostname header value if exists. Note: Changing this does NOT change host in RequestUri. Users can set new RequestUri separately. Declaration public string Host { get; set; } Property Value Type Description String Is100Continue Did server responsed positively for 100 continue request? Declaration public bool Is100Continue { get; } Property Value Type Description Boolean IsHttps Is Https? Declaration public bool IsHttps { get; } Property Value Type Description Boolean IsMultipartFormData Does this request contain multipart/form-data? Declaration public bool IsMultipartFormData { get; } Property Value Type Description Boolean Method Request Method. Declaration public string Method { get; set; } Property Value Type Description String OriginalUrl The original request Url. Declaration public string OriginalUrl { get; set; } Property Value Type Description String RequestUri Request HTTP Uri. Declaration public Uri RequestUri { get; set; } Property Value Type Description Uri UpgradeToWebSocket Does this request has an upgrade to websocket header? Declaration public bool UpgradeToWebSocket { get; } Property Value Type Description Boolean Url Request Url. Declaration public string Url { get; } Property Value Type Description String"
},
"api/Titanium.Web.Proxy.Http.RequestResponseBase.html": {
"href": "api/Titanium.Web.Proxy.Http.RequestResponseBase.html",
"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 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()"
"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 Byte [] BodyInternal Cached body content as byte array. Declaration protected byte[] BodyInternal { get; } Property Value Type Description 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 OriginalIsBodyRead Store whether the original request/response body was read by user. We need this detail to syphon out attached tcp connection for reuse. Declaration public bool OriginalIsBodyRead { get; } 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": {
"href": "api/Titanium.Web.Proxy.Http.Response.html",
"title": "Class Response | Titanium Web Proxy",
"keywords": "Class Response Http(s) response object Inheritance Object RequestResponseBase Response ConnectResponse GenericResponse OkResponse RedirectResponse Inherited Members 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 Assembly : Titanium.Web.Proxy.dll Syntax [TypeConverter(typeof(ExpandableObjectConverter))] public class Response : RequestResponseBase Constructors Response() Constructor. Declaration public Response() Response(Byte[]) Constructor. Declaration public Response(byte[] body) Parameters Type Name Description System.Byte [] body Properties ExpectationFailed expectation failed returned by server? Declaration public bool ExpectationFailed { get; } Property Value Type Description Boolean HasBody Has response body? Declaration public override bool HasBody { get; } Property Value Type Description Boolean Overrides RequestResponseBase.HasBody HeaderText Gets the header text. Declaration public override string HeaderText { get; } Property Value Type Description String Overrides RequestResponseBase.HeaderText Is100Continue Is response 100-continue Declaration public bool Is100Continue { get; } Property Value Type Description Boolean KeepAlive Keep the connection alive? Declaration public bool KeepAlive { get; } Property Value Type Description Boolean StatusCode Response Status Code. Declaration public int StatusCode { get; set; } Property Value Type Description Int32 StatusDescription Response Status description. Declaration public string StatusDescription { get; set; } Property Value Type Description String"
"keywords": "Class Response Http(s) response object Inheritance Object RequestResponseBase Response ConnectResponse GenericResponse OkResponse RedirectResponse Inherited Members RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 Assembly : Titanium.Web.Proxy.dll Syntax [TypeConverter(typeof(ExpandableObjectConverter))] public class Response : RequestResponseBase Constructors Response() Constructor. Declaration public Response() Response(Byte[]) Constructor. Declaration public Response(byte[] body) Parameters Type Name Description Byte [] body Properties ExpectationFailed expectation failed returned by server? Declaration public bool ExpectationFailed { get; } Property Value Type Description Boolean HasBody Has response body? Declaration public override bool HasBody { get; } Property Value Type Description Boolean Overrides RequestResponseBase.HasBody HeaderText Gets the header text. Declaration public override string HeaderText { get; } Property Value Type Description String Overrides RequestResponseBase.HeaderText Is100Continue Is response 100-continue Declaration public bool Is100Continue { get; } Property Value Type Description Boolean KeepAlive Keep the connection alive? Declaration public bool KeepAlive { get; } Property Value Type Description Boolean StatusCode Response Status Code. Declaration public int StatusCode { get; set; } Property Value Type Description Int32 StatusDescription Response Status description. Declaration public string StatusDescription { get; set; } Property Value Type Description String"
},
"api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html": {
"href": "api/Titanium.Web.Proxy.Http.Responses.GenericResponse.html",
"title": "Class GenericResponse | Titanium Web Proxy",
"keywords": "Class GenericResponse Anything other than a 200 or 302 response Inheritance Object RequestResponseBase Response GenericResponse 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 class GenericResponse : Response Constructors GenericResponse(Int32, String) Constructor. Declaration public GenericResponse(int statusCode, string statusDescription) Parameters Type Name Description Int32 statusCode String statusDescription GenericResponse(HttpStatusCode) Constructor. Declaration public GenericResponse(HttpStatusCode status) Parameters Type Name Description HttpStatusCode status"
"keywords": "Class GenericResponse Anything other than a 200 or 302 response Inheritance Object RequestResponseBase Response GenericResponse Inherited Members Response.StatusCode Response.StatusDescription Response.HasBody Response.KeepAlive Response.Is100Continue Response.ExpectationFailed Response.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 class GenericResponse : Response Constructors GenericResponse(Int32, String) Constructor. Declaration public GenericResponse(int statusCode, string statusDescription) Parameters Type Name Description Int32 statusCode String statusDescription GenericResponse(HttpStatusCode) Constructor. Declaration public GenericResponse(HttpStatusCode status) Parameters Type Name Description HttpStatusCode status"
},
"api/Titanium.Web.Proxy.Http.Responses.html": {
"href": "api/Titanium.Web.Proxy.Http.Responses.html",
......@@ -137,12 +137,12 @@
"api/Titanium.Web.Proxy.Http.Responses.OkResponse.html": {
"href": "api/Titanium.Web.Proxy.Http.Responses.OkResponse.html",
"title": "Class OkResponse | Titanium Web Proxy",
"keywords": "Class OkResponse 200 Ok response Inheritance Object RequestResponseBase Response OkResponse 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 OkResponse : Response Constructors OkResponse() Constructor. Declaration public OkResponse() OkResponse(Byte[]) Constructor. Declaration public OkResponse(byte[] body) Parameters Type Name Description System.Byte [] body"
"keywords": "Class OkResponse 200 Ok response Inheritance Object RequestResponseBase Response OkResponse Inherited Members Response.StatusCode Response.StatusDescription Response.HasBody Response.KeepAlive Response.Is100Continue Response.ExpectationFailed Response.HeaderText RequestResponseBase.BodyInternal RequestResponseBase.OriginalIsBodyRead 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 OkResponse : Response Constructors OkResponse() Constructor. Declaration public OkResponse() OkResponse(Byte[]) Constructor. Declaration public OkResponse(byte[] body) Parameters Type Name Description Byte [] body"
},
"api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html": {
"href": "api/Titanium.Web.Proxy.Http.Responses.RedirectResponse.html",
"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() Initializes a new instance of the RedirectResponse class. 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.OriginalIsBodyRead 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": {
"href": "api/Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html",
......@@ -162,7 +162,7 @@
"api/Titanium.Web.Proxy.Models.HttpHeader.html": {
"href": "api/Titanium.Web.Proxy.Models.HttpHeader.html",
"title": "Class HttpHeader | Titanium Web Proxy",
"keywords": "Class HttpHeader Http Header object used by proxy Inheritance Object HttpHeader Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Models Assembly : Titanium.Web.Proxy.dll Syntax public class HttpHeader Constructors HttpHeader(String, String) Initialize a new instance. Declaration public HttpHeader(string name, string value) Parameters Type Name Description String name Header name. String value Header value. Properties Name Header Name. Declaration public string Name { get; set; } Property Value Type Description String Value Header Value. Declaration public string Value { get; set; } Property Value Type Description String Methods ToString() Returns header as a valid header string. Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()"
"keywords": "Class HttpHeader Http Header object used by proxy Inheritance Object HttpHeader Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Models Assembly : Titanium.Web.Proxy.dll Syntax public class HttpHeader Constructors HttpHeader(String, String) Initialize a new instance. Declaration public HttpHeader(string name, string value) Parameters Type Name Description String name Header name. String value Header value. Fields HttpHeaderOverhead HPACK: Header Compression for HTTP/2 Section 4.1. Calculating Table Size The additional 32 octets account for an estimated overhead associated with an entry. Declaration public const int HttpHeaderOverhead = 32 Field Value Type Description Int32 Properties Name Header Name. Declaration public string Name { get; set; } Property Value Type Description String Size Declaration public int Size { get; } Property Value Type Description Int32 Value Header Value. Declaration public string Value { get; set; } Property Value Type Description String Methods SizeOf(String, String) Declaration public static int SizeOf(string name, string value) Parameters Type Name Description String name String value Returns Type Description Int32 ToString() Returns header as a valid header string. Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()"
},
"api/Titanium.Web.Proxy.Models.ProxyEndPoint.html": {
"href": "api/Titanium.Web.Proxy.Models.ProxyEndPoint.html",
......@@ -192,6 +192,6 @@
"api/Titanium.Web.Proxy.ProxyServer.html": {
"href": "api/Titanium.Web.Proxy.ProxyServer.html",
"title": "Class ProxyServer | Titanium Web Proxy",
"keywords": "Class ProxyServer This class is the backbone of proxy. One can create as many instances as needed. However care should be taken to avoid using the same listening ports across multiple instances. Inheritance Object ProxyServer Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy Assembly : Titanium.Web.Proxy.dll Syntax public class ProxyServer : IDisposable Constructors ProxyServer(Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? ProxyServer(String, String, Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description String rootCertificateName Name of the root certificate. String rootCertificateIssuerName Name of the root certificate issuer. Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? Properties 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"
"keywords": "Class ProxyServer This class is the backbone of proxy. One can create as many instances as needed. However care should be taken to avoid using the same listening ports across multiple instances. Inheritance Object ProxyServer Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy Assembly : Titanium.Web.Proxy.dll Syntax public class ProxyServer : IDisposable Constructors ProxyServer(Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? ProxyServer(String, String, Boolean, Boolean, Boolean) Initializes a new instance of ProxyServer class with provided parameters. Declaration public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description String rootCertificateName Name of the root certificate. String rootCertificateIssuerName Name of the root certificate issuer. Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? Properties BufferPool The buffer pool used throughout this proxy instance. Set custom implementations by implementing this interface. By default this uses DefaultBufferPool implementation available in StreamExtended library package. Declaration public IBufferPool BufferPool { get; set; } Property Value Type Description StreamExtended.IBufferPool BufferSize Buffer size in bytes used throughout this proxy. Default value is 8192 bytes. Declaration public int BufferSize { get; set; } Property Value Type Description Int32 CertificateManager Manages certificates used by this proxy. Declaration public CertificateManager CertificateManager { get; } Property Value Type Description CertificateManager CheckCertificateRevocation Should we check for certificare revocation during SSL authentication to servers Note: If enabled can reduce performance. Defaults to false. Declaration public X509RevocationMode CheckCertificateRevocation { get; set; } Property Value Type Description X509RevocationMode ClientConnectionCount Total number of active client connections. Declaration public int ClientConnectionCount { get; } Property Value Type Description Int32 ConnectionTimeOutSeconds Seconds client/server connection are to be kept alive when waiting for read/write to complete. This will also determine the pool eviction time when connection pool is enabled. Default value is 60 seconds. Declaration public int ConnectionTimeOutSeconds { get; set; } Property Value Type Description Int32 Enable100ContinueBehaviour Does this proxy uses the HTTP protocol 100 continue behaviour strictly? Broken 100 contunue implementations on server/client may cause problems if enabled. Defaults to false. Declaration public bool Enable100ContinueBehaviour { get; set; } Property Value Type Description Boolean EnableConnectionPool Should we enable experimental server connection pool? Defaults to disable. Declaration public bool EnableConnectionPool { get; set; } Property Value Type Description Boolean EnableWinAuth Enable disable Windows Authentication (NTLM/Kerberos). Note: NTLM/Kerberos will always send local credentials of current user running the proxy process. This is because a man in middle attack with Windows domain authentication is not currently supported. Defaults to false. Declaration public bool EnableWinAuth { get; set; } Property Value Type Description Boolean ExceptionFunc Callback for error events in this proxy instance. Declaration public ExceptionHandler ExceptionFunc { get; set; } Property Value Type Description ExceptionHandler ForwardToUpstreamGateway Gets or sets a value indicating whether requests will be chained to upstream gateway. Defaults to false. Declaration public bool ForwardToUpstreamGateway { get; set; } Property Value Type Description Boolean GetCustomUpStreamProxyFunc A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. User should return the ExternalProxy object with valid credentials. Declaration public Func<SessionEventArgsBase, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , Task < ExternalProxy >> MaxCachedConnections Maximum number of concurrent connections per remote host in cache. Only valid when connection pooling is enabled. Default value is 2. Declaration public int MaxCachedConnections { get; set; } Property Value Type Description Int32 ProxyAuthenticationRealm Realm used during Proxy Basic Authentication. Declaration public string ProxyAuthenticationRealm { get; set; } Property Value Type Description String ProxyAuthenticationSchemes A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. Works in relation with ProxySchemeAuthenticateFunc. Declaration public IEnumerable<string> ProxyAuthenticationSchemes { get; set; } Property Value Type Description IEnumerable < String > ProxyBasicAuthenticateFunc A callback to authenticate proxy clients via basic authentication. Parameters are username and password as provided by client. Should return true for successful authentication. Declaration public Func<SessionEventArgsBase, string, string, Task<bool>> ProxyBasicAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < Boolean >> ProxyEndPoints A list of IpAddress and port this proxy is listening to. Declaration public List<ProxyEndPoint> ProxyEndPoints { get; set; } Property Value Type Description List < ProxyEndPoint > ProxyRunning Is the proxy currently running? Declaration public bool ProxyRunning { get; } Property Value Type Description Boolean ProxySchemeAuthenticateFunc A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. Parameters are current working session, schemeType, and token as provided by a calling client. Should return success for successful authentication, continuation if the package requests, or failure. Declaration public Func<SessionEventArgsBase, string, string, Task<ProxyAuthenticationContext>> ProxySchemeAuthenticateFunc { get; set; } Property Value Type Description Func < SessionEventArgsBase , String , String , Task < ProxyAuthenticationContext >> 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 OnClientConnectionCreate Customize TcpClient used for client connection upon create. Declaration public event AsyncEventHandler<TcpClient> OnClientConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > OnServerConnectionCreate Customize TcpClient used for server connection upon create. Declaration public event AsyncEventHandler<TcpClient> OnServerConnectionCreate Event Type Type Description AsyncEventHandler < TcpClient > ServerCertificateValidationCallback Event to override the default verification logic of remote SSL certificate received during authentication. Declaration public event AsyncEventHandler<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"
}
}
......@@ -544,7 +544,7 @@ $(function () {
if ($('footer').is(':visible')) {
$(".sideaffix").css("bottom", "70px");
}
$('#affix a').click((e) => {
$('#affix a').click(function() {
var scrollspy = $('[data-spy="scroll"]').data()['bs.scrollspy'];
var target = e.target.hash;
if (scrollspy && target) {
......
......@@ -247,12 +247,12 @@ references:
commentId: T:Titanium.Web.Proxy.EventArguments.SessionEventArgs
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs
nameWithType: SessionEventArgs
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.ExceptionHandler)
name: SessionEventArgs(Int32, ProxyEndPoint, Request, CancellationTokenSource, ExceptionHandler)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_System_Int32_Titanium_Web_Proxy_Models_ProxyEndPoint_Titanium_Web_Proxy_Http_Request_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_ExceptionHandler_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.ExceptionHandler)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.SessionEventArgs(System.Int32, Titanium.Web.Proxy.Models.ProxyEndPoint, Titanium.Web.Proxy.Http.Request, System.Threading.CancellationTokenSource, Titanium.Web.Proxy.ExceptionHandler)
nameWithType: SessionEventArgs.SessionEventArgs(Int32, ProxyEndPoint, Request, CancellationTokenSource, ExceptionHandler)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource)
name: SessionEventArgs(ProxyServer, ProxyEndPoint, Request, CancellationTokenSource)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_Titanium_Web_Proxy_ProxyServer_Titanium_Web_Proxy_Models_ProxyEndPoint_Titanium_Web_Proxy_Http_Request_System_Threading_CancellationTokenSource_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,Titanium.Web.Proxy.Http.Request,System.Threading.CancellationTokenSource)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.SessionEventArgs(Titanium.Web.Proxy.ProxyServer, Titanium.Web.Proxy.Models.ProxyEndPoint, Titanium.Web.Proxy.Http.Request, System.Threading.CancellationTokenSource)
nameWithType: SessionEventArgs.SessionEventArgs(ProxyServer, ProxyEndPoint, Request, CancellationTokenSource)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.#ctor*
name: SessionEventArgs
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs__ctor_
......@@ -273,24 +273,24 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Dispose
nameWithType: SessionEventArgs.Dispose
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name: GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_Byte___System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name.vb: GenericResponse(Byte(), HttpStatusCode, Dictionary(Of String, HttpHeader))
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[], System.Net.HttpStatusCode, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte(), System.Net.HttpStatusCode, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader))
nameWithType: SessionEventArgs.GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>)
nameWithType.vb: SessionEventArgs.GenericResponse(Byte(), HttpStatusCode, Dictionary(Of String, HttpHeader))
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name: GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_String_System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name.vb: GenericResponse(String, HttpStatusCode, Dictionary(Of String, HttpHeader))
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String, System.Net.HttpStatusCode, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String, System.Net.HttpStatusCode, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader))
nameWithType: SessionEventArgs.GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>)
nameWithType.vb: SessionEventArgs.GenericResponse(String, HttpStatusCode, Dictionary(Of String, HttpHeader))
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name: GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_Byte___System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[],System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name.vb: GenericResponse(Byte(), HttpStatusCode, Dictionary(Of String, HttpHeader), Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte[], System.Net.HttpStatusCode, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>, System.Boolean)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.Byte(), System.Net.HttpStatusCode, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader), System.Boolean)
nameWithType: SessionEventArgs.GenericResponse(Byte[], HttpStatusCode, Dictionary<String, HttpHeader>, Boolean)
nameWithType.vb: SessionEventArgs.GenericResponse(Byte(), HttpStatusCode, Dictionary(Of String, HttpHeader), Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name: GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_System_String_System_Net_HttpStatusCode_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String,System.Net.HttpStatusCode,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name.vb: GenericResponse(String, HttpStatusCode, Dictionary(Of String, HttpHeader), Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String, System.Net.HttpStatusCode, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>, System.Boolean)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse(System.String, System.Net.HttpStatusCode, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader), System.Boolean)
nameWithType: SessionEventArgs.GenericResponse(String, HttpStatusCode, Dictionary<String, HttpHeader>, Boolean)
nameWithType.vb: SessionEventArgs.GenericResponse(String, HttpStatusCode, Dictionary(Of String, HttpHeader), Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.GenericResponse*
name: GenericResponse
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_GenericResponse_
......@@ -356,24 +356,24 @@ references:
commentId: E:Titanium.Web.Proxy.EventArguments.SessionEventArgs.MultipartRequestPartSent
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.MultipartRequestPartSent
nameWithType: SessionEventArgs.MultipartRequestPartSent
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name: Ok(Byte[], Dictionary<String, HttpHeader>)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_Byte___System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name.vb: Ok(Byte(), Dictionary(Of String, HttpHeader))
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[], System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte(), System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader))
nameWithType: SessionEventArgs.Ok(Byte[], Dictionary<String, HttpHeader>)
nameWithType.vb: SessionEventArgs.Ok(Byte(), Dictionary(Of String, HttpHeader))
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name: Ok(String, Dictionary<String, HttpHeader>)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_String_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader})
name.vb: Ok(String, Dictionary(Of String, HttpHeader))
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader))
nameWithType: SessionEventArgs.Ok(String, Dictionary<String, HttpHeader>)
nameWithType.vb: SessionEventArgs.Ok(String, Dictionary(Of String, HttpHeader))
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name: Ok(Byte[], Dictionary<String, HttpHeader>, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_Byte___System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[],System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name.vb: Ok(Byte(), Dictionary(Of String, HttpHeader), Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte[], System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>, System.Boolean)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.Byte(), System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader), System.Boolean)
nameWithType: SessionEventArgs.Ok(Byte[], Dictionary<String, HttpHeader>, Boolean)
nameWithType.vb: SessionEventArgs.Ok(Byte(), Dictionary(Of String, HttpHeader), Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name: Ok(String, Dictionary<String, HttpHeader>, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_System_String_System_Collections_Generic_Dictionary_System_String_Titanium_Web_Proxy_Models_HttpHeader__System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String,System.Collections.Generic.Dictionary{System.String,Titanium.Web.Proxy.Models.HttpHeader},System.Boolean)
name.vb: Ok(String, Dictionary(Of String, HttpHeader), Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String, System.Collections.Generic.Dictionary<System.String, Titanium.Web.Proxy.Models.HttpHeader>, System.Boolean)
fullName.vb: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok(System.String, System.Collections.Generic.Dictionary(Of System.String, Titanium.Web.Proxy.Models.HttpHeader), System.Boolean)
nameWithType: SessionEventArgs.Ok(String, Dictionary<String, HttpHeader>, Boolean)
nameWithType.vb: SessionEventArgs.Ok(String, Dictionary(Of String, HttpHeader), Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok*
name: Ok
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Ok_
......@@ -381,12 +381,12 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Ok
nameWithType: SessionEventArgs.Ok
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String)
name: Redirect(String)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_System_String_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String)
nameWithType: SessionEventArgs.Redirect(String)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String,System.Boolean)
name: Redirect(String, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_System_String_System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String,System.Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect(System.String, System.Boolean)
nameWithType: SessionEventArgs.Redirect(String, Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Redirect*
name: Redirect
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Redirect_
......@@ -407,12 +407,12 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.ReRequest
nameWithType: SessionEventArgs.ReRequest
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response)
name: Respond(Response)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_Titanium_Web_Proxy_Http_Response_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response)
nameWithType: SessionEventArgs.Respond(Response)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response,System.Boolean)
name: Respond(Response, Boolean)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_Titanium_Web_Proxy_Http_Response_System_Boolean_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response,System.Boolean)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond(Titanium.Web.Proxy.Http.Response, System.Boolean)
nameWithType: SessionEventArgs.Respond(Response, Boolean)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgs.Respond*
name: Respond
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html#Titanium_Web_Proxy_EventArguments_SessionEventArgs_Respond_
......@@ -497,12 +497,12 @@ references:
commentId: T:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase
nameWithType: SessionEventArgsBase
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request,Titanium.Web.Proxy.ExceptionHandler)
name: SessionEventArgsBase(Int32, ProxyEndPoint, CancellationTokenSource, Request, ExceptionHandler)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_System_Int32_Titanium_Web_Proxy_Models_ProxyEndPoint_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_Http_Request_Titanium_Web_Proxy_ExceptionHandler_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(System.Int32,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request,Titanium.Web.Proxy.ExceptionHandler)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.SessionEventArgsBase(System.Int32, Titanium.Web.Proxy.Models.ProxyEndPoint, System.Threading.CancellationTokenSource, Titanium.Web.Proxy.Http.Request, Titanium.Web.Proxy.ExceptionHandler)
nameWithType: SessionEventArgsBase.SessionEventArgsBase(Int32, ProxyEndPoint, CancellationTokenSource, Request, ExceptionHandler)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request)
name: SessionEventArgsBase(ProxyServer, ProxyEndPoint, CancellationTokenSource, Request)
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_Titanium_Web_Proxy_ProxyServer_Titanium_Web_Proxy_Models_ProxyEndPoint_System_Threading_CancellationTokenSource_Titanium_Web_Proxy_Http_Request_
commentId: M:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor(Titanium.Web.Proxy.ProxyServer,Titanium.Web.Proxy.Models.ProxyEndPoint,System.Threading.CancellationTokenSource,Titanium.Web.Proxy.Http.Request)
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.SessionEventArgsBase(Titanium.Web.Proxy.ProxyServer, Titanium.Web.Proxy.Models.ProxyEndPoint, System.Threading.CancellationTokenSource, Titanium.Web.Proxy.Http.Request)
nameWithType: SessionEventArgsBase.SessionEventArgsBase(ProxyServer, ProxyEndPoint, CancellationTokenSource, Request)
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.#ctor*
name: SessionEventArgsBase
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase__ctor_
......@@ -510,12 +510,18 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.SessionEventArgsBase
nameWithType: SessionEventArgsBase.SessionEventArgsBase
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.BufferSize
name: BufferSize
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_BufferSize
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.BufferSize
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.BufferSize
nameWithType: SessionEventArgsBase.BufferSize
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferPool
name: bufferPool
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferPool
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferPool
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferPool
nameWithType: SessionEventArgsBase.bufferPool
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferSize
name: bufferSize
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_bufferSize
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferSize
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.bufferSize
nameWithType: SessionEventArgsBase.bufferSize
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ClientEndPoint
name: ClientEndPoint
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ClientEndPoint
......@@ -580,12 +586,12 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.Exception
nameWithType: SessionEventArgsBase.Exception
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc
name: ExceptionFunc
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_ExceptionFunc
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.ExceptionFunc
nameWithType: SessionEventArgsBase.ExceptionFunc
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.exceptionFunc
name: exceptionFunc
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_exceptionFunc
commentId: F:Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.exceptionFunc
fullName: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.exceptionFunc
nameWithType: SessionEventArgsBase.exceptionFunc
- uid: Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.IsHttps
name: IsHttps
href: api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html#Titanium_Web_Proxy_EventArguments_SessionEventArgsBase_IsHttps
......@@ -1688,6 +1694,19 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.Http.RequestResponseBase.KeepBody
nameWithType: RequestResponseBase.KeepBody
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead
name: OriginalIsBodyRead
href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead
commentId: P:Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead
fullName: Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead
nameWithType: RequestResponseBase.OriginalIsBodyRead
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead*
name: OriginalIsBodyRead
href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_OriginalIsBodyRead_
commentId: Overload:Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead
isSpec: "True"
fullName: Titanium.Web.Proxy.Http.RequestResponseBase.OriginalIsBodyRead
nameWithType: RequestResponseBase.OriginalIsBodyRead
- uid: Titanium.Web.Proxy.Http.RequestResponseBase.ToString
name: ToString()
href: api/Titanium.Web.Proxy.Http.RequestResponseBase.html#Titanium_Web_Proxy_Http_RequestResponseBase_ToString
......@@ -2064,6 +2083,12 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.HttpHeader
nameWithType: HttpHeader.HttpHeader
- uid: Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
name: HttpHeaderOverhead
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_HttpHeaderOverhead
commentId: F:Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
fullName: Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
nameWithType: HttpHeader.HttpHeaderOverhead
- uid: Titanium.Web.Proxy.Models.HttpHeader.Name
name: Name
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Name
......@@ -2077,6 +2102,32 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.Name
nameWithType: HttpHeader.Name
- uid: Titanium.Web.Proxy.Models.HttpHeader.Size
name: Size
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Size
commentId: P:Titanium.Web.Proxy.Models.HttpHeader.Size
fullName: Titanium.Web.Proxy.Models.HttpHeader.Size
nameWithType: HttpHeader.Size
- uid: Titanium.Web.Proxy.Models.HttpHeader.Size*
name: Size
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Size_
commentId: Overload:Titanium.Web.Proxy.Models.HttpHeader.Size
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.Size
nameWithType: HttpHeader.Size
- uid: Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)
name: SizeOf(String, String)
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_SizeOf_System_String_System_String_
commentId: M:Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)
fullName: Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String, System.String)
nameWithType: HttpHeader.SizeOf(String, String)
- uid: Titanium.Web.Proxy.Models.HttpHeader.SizeOf*
name: SizeOf
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_SizeOf_
commentId: Overload:Titanium.Web.Proxy.Models.HttpHeader.SizeOf
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.SizeOf
nameWithType: HttpHeader.SizeOf
- uid: Titanium.Web.Proxy.Models.HttpHeader.ToString
name: ToString()
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_ToString
......@@ -2571,19 +2622,6 @@ references:
commentId: E:Titanium.Web.Proxy.ProxyServer.AfterResponse
fullName: Titanium.Web.Proxy.ProxyServer.AfterResponse
nameWithType: ProxyServer.AfterResponse
- uid: Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc
name: AuthenticateUserFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_AuthenticateUserFunc
commentId: P:Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc
fullName: Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc
nameWithType: ProxyServer.AuthenticateUserFunc
- uid: Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc*
name: AuthenticateUserFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_AuthenticateUserFunc_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.AuthenticateUserFunc
nameWithType: ProxyServer.AuthenticateUserFunc
- uid: Titanium.Web.Proxy.ProxyServer.BeforeRequest
name: BeforeRequest
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_BeforeRequest
......@@ -2596,6 +2634,19 @@ references:
commentId: E:Titanium.Web.Proxy.ProxyServer.BeforeResponse
fullName: Titanium.Web.Proxy.ProxyServer.BeforeResponse
nameWithType: ProxyServer.BeforeResponse
- uid: Titanium.Web.Proxy.ProxyServer.BufferPool
name: BufferPool
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_BufferPool
commentId: P:Titanium.Web.Proxy.ProxyServer.BufferPool
fullName: Titanium.Web.Proxy.ProxyServer.BufferPool
nameWithType: ProxyServer.BufferPool
- uid: Titanium.Web.Proxy.ProxyServer.BufferPool*
name: BufferPool
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_BufferPool_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.BufferPool
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.BufferPool
nameWithType: ProxyServer.BufferPool
- uid: Titanium.Web.Proxy.ProxyServer.BufferSize
name: BufferSize
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_BufferSize
......@@ -2751,6 +2802,19 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.Enable100ContinueBehaviour
nameWithType: ProxyServer.Enable100ContinueBehaviour
- uid: Titanium.Web.Proxy.ProxyServer.EnableConnectionPool
name: EnableConnectionPool
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableConnectionPool
commentId: P:Titanium.Web.Proxy.ProxyServer.EnableConnectionPool
fullName: Titanium.Web.Proxy.ProxyServer.EnableConnectionPool
nameWithType: ProxyServer.EnableConnectionPool
- uid: Titanium.Web.Proxy.ProxyServer.EnableConnectionPool*
name: EnableConnectionPool
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableConnectionPool_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.EnableConnectionPool
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.EnableConnectionPool
nameWithType: ProxyServer.EnableConnectionPool
- uid: Titanium.Web.Proxy.ProxyServer.EnableWinAuth
name: EnableWinAuth
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_EnableWinAuth
......@@ -2803,6 +2867,70 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.GetCustomUpStreamProxyFunc
nameWithType: ProxyServer.GetCustomUpStreamProxyFunc
- uid: Titanium.Web.Proxy.ProxyServer.MaxCachedConnections
name: MaxCachedConnections
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_MaxCachedConnections
commentId: P:Titanium.Web.Proxy.ProxyServer.MaxCachedConnections
fullName: Titanium.Web.Proxy.ProxyServer.MaxCachedConnections
nameWithType: ProxyServer.MaxCachedConnections
- uid: Titanium.Web.Proxy.ProxyServer.MaxCachedConnections*
name: MaxCachedConnections
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_MaxCachedConnections_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.MaxCachedConnections
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.MaxCachedConnections
nameWithType: ProxyServer.MaxCachedConnections
- uid: Titanium.Web.Proxy.ProxyServer.OnClientConnectionCreate
name: OnClientConnectionCreate
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_OnClientConnectionCreate
commentId: E:Titanium.Web.Proxy.ProxyServer.OnClientConnectionCreate
fullName: Titanium.Web.Proxy.ProxyServer.OnClientConnectionCreate
nameWithType: ProxyServer.OnClientConnectionCreate
- uid: Titanium.Web.Proxy.ProxyServer.OnServerConnectionCreate
name: OnServerConnectionCreate
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_OnServerConnectionCreate
commentId: E:Titanium.Web.Proxy.ProxyServer.OnServerConnectionCreate
fullName: Titanium.Web.Proxy.ProxyServer.OnServerConnectionCreate
nameWithType: ProxyServer.OnServerConnectionCreate
- uid: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm
name: ProxyAuthenticationRealm
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationRealm
commentId: P:Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm
fullName: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm
nameWithType: ProxyServer.ProxyAuthenticationRealm
- uid: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm*
name: ProxyAuthenticationRealm
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationRealm_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationRealm
nameWithType: ProxyServer.ProxyAuthenticationRealm
- uid: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes
name: ProxyAuthenticationSchemes
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationSchemes
commentId: P:Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes
fullName: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes
nameWithType: ProxyServer.ProxyAuthenticationSchemes
- uid: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes*
name: ProxyAuthenticationSchemes
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyAuthenticationSchemes_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyAuthenticationSchemes
nameWithType: ProxyServer.ProxyAuthenticationSchemes
- uid: Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc
name: ProxyBasicAuthenticateFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyBasicAuthenticateFunc
commentId: P:Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc
fullName: Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc
nameWithType: ProxyServer.ProxyBasicAuthenticateFunc
- uid: Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc*
name: ProxyBasicAuthenticateFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyBasicAuthenticateFunc_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyBasicAuthenticateFunc
nameWithType: ProxyServer.ProxyBasicAuthenticateFunc
- uid: Titanium.Web.Proxy.ProxyServer.ProxyEndPoints
name: ProxyEndPoints
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyEndPoints
......@@ -2816,19 +2944,6 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyEndPoints
nameWithType: ProxyServer.ProxyEndPoints
- uid: Titanium.Web.Proxy.ProxyServer.ProxyRealm
name: ProxyRealm
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyRealm
commentId: P:Titanium.Web.Proxy.ProxyServer.ProxyRealm
fullName: Titanium.Web.Proxy.ProxyServer.ProxyRealm
nameWithType: ProxyServer.ProxyRealm
- uid: Titanium.Web.Proxy.ProxyServer.ProxyRealm*
name: ProxyRealm
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyRealm_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.ProxyRealm
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyRealm
nameWithType: ProxyServer.ProxyRealm
- uid: Titanium.Web.Proxy.ProxyServer.ProxyRunning
name: ProxyRunning
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxyRunning
......@@ -2842,6 +2957,19 @@ references:
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxyRunning
nameWithType: ProxyServer.ProxyRunning
- uid: Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc
name: ProxySchemeAuthenticateFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxySchemeAuthenticateFunc
commentId: P:Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc
fullName: Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc
nameWithType: ProxyServer.ProxySchemeAuthenticateFunc
- uid: Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc*
name: ProxySchemeAuthenticateFunc
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_ProxySchemeAuthenticateFunc_
commentId: Overload:Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc
isSpec: "True"
fullName: Titanium.Web.Proxy.ProxyServer.ProxySchemeAuthenticateFunc
nameWithType: ProxyServer.ProxySchemeAuthenticateFunc
- uid: Titanium.Web.Proxy.ProxyServer.RemoveEndPoint(Titanium.Web.Proxy.Models.ProxyEndPoint)
name: RemoveEndPoint(ProxyEndPoint)
href: api/Titanium.Web.Proxy.ProxyServer.html#Titanium_Web_Proxy_ProxyServer_RemoveEndPoint_Titanium_Web_Proxy_Models_ProxyEndPoint_
......
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