Unverified Commit d476e945 authored by honfika's avatar honfika Committed by GitHub

Merge pull request #605 from justcoding121/master

Merge to beta
parents a9412640 4700deea
## Titanium Web Proxy
### Note: This Project is no longer maintained. Any pull requests for fixes are welcome.
A lightweight HTTP(S) proxy server written in C#.
<a href="https://ci.appveyor.com/project/justcoding121/titanium-web-proxy">![Build Status](https://ci.appveyor.com/api/projects/status/p5vvtbpx9yp250ol?svg=true)</a> [![Join the chat at https://gitter.im/Titanium-Web-Proxy/Lobby](https://badges.gitter.im/Titanium-Web-Proxy/Lobby.svg)](https://gitter.im/Titanium-Web-Proxy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
......
......@@ -136,7 +136,7 @@
</span>
<a id="Titanium_Web_Proxy_EventArguments_CertificateSelectionEventArgs_AcceptableIssuers_" data-uid="Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.AcceptableIssuers*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_CertificateSelectionEventArgs_AcceptableIssuers" data-uid="Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.AcceptableIssuers">AcceptableIssuers</h4>
<div class="markdown level1 summary"><p>Acceptable issuers as listed by remoted server.</p>
<div class="markdown level1 summary"><p>Acceptable issuers as listed by remote server.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
......@@ -100,13 +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_bufferPool">SessionEventArgsBase.bufferPool</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>
<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_TimeLine">SessionEventArgsBase.TimeLine</a>
......@@ -255,7 +255,7 @@ Default is true.</p>
</span>
<a id="Titanium_Web_Proxy_EventArguments_TunnelConnectSessionEventArgs_IsHttpsConnect_" data-uid="Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.IsHttpsConnect*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_TunnelConnectSessionEventArgs_IsHttpsConnect" data-uid="Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.IsHttpsConnect">IsHttpsConnect</h4>
<div class="markdown level1 summary"><p>Is this a connect request to secure HTTP server? Or is it to someother protocol.</p>
<div class="markdown level1 summary"><p>Is this a connect request to secure HTTP server? Or is it to some other protocol.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
......@@ -236,7 +236,7 @@
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">message</span></td>
<td><p>Excception message</p>
<td><p>Exception message</p>
</td>
</tr>
<tr>
......
......@@ -107,6 +107,9 @@
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.Request.html#Titanium_Web_Proxy_Http_Request_OriginalUrl">Request.OriginalUrl</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.Request.html#Titanium_Web_Proxy_Http_Request_RequestUriString">Request.RequestUriString</a>
</div>
<div>
<a class="xref" href="Titanium.Web.Proxy.Http.Request.html#Titanium_Web_Proxy_Http_Request_HasBody">Request.HasBody</a>
</div>
......@@ -222,7 +225,7 @@
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Http_ConnectRequest_ClientHelloInfo.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Http.ConnectRequest.ClientHelloInfo%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http/ConnectRequest.cs/#L15">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http/ConnectRequest.cs/#L17">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Http_ConnectRequest_ClientHelloInfo_" data-uid="Titanium.Web.Proxy.Http.ConnectRequest.ClientHelloInfo*"></a>
<h4 id="Titanium_Web_Proxy_Http_ConnectRequest_ClientHelloInfo" data-uid="Titanium.Web.Proxy.Http.ConnectRequest.ClientHelloInfo">ClientHelloInfo</h4>
......@@ -242,7 +245,37 @@
</thead>
<tbody>
<tr>
<td><span class="xref">StreamExtended.ClientHelloInfo</span></td>
<td><span class="xref">ClientHelloInfo</span></td>
<td></td>
</tr>
</tbody>
</table>
<span class="small pull-right mobile-hide">
<span class="divider">|</span>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Http_ConnectRequest_TunnelType.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Http.ConnectRequest.TunnelType%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http/ConnectRequest.cs/#L15">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Http_ConnectRequest_TunnelType_" data-uid="Titanium.Web.Proxy.Http.ConnectRequest.TunnelType*"></a>
<h4 id="Titanium_Web_Proxy_Http_ConnectRequest_TunnelType" data-uid="Titanium.Web.Proxy.Http.ConnectRequest.TunnelType">TunnelType</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 TunnelType TunnelType { 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><span class="xref">TunnelType</span></td>
<td></td>
</tr>
</tbody>
......
......@@ -201,7 +201,7 @@
</thead>
<tbody>
<tr>
<td><span class="xref">StreamExtended.ServerHelloInfo</span></td>
<td><span class="xref">ServerHelloInfo</span></td>
<td></td>
</tr>
</tbody>
......
......@@ -517,7 +517,7 @@ public class HeaderCollection : IEnumerable&lt;HttpHeader&gt;, IEnumerable</code
<a id="Titanium_Web_Proxy_Http_HeaderCollection_GetHeaders_" data-uid="Titanium.Web.Proxy.Http.HeaderCollection.GetHeaders*"></a>
<h4 id="Titanium_Web_Proxy_Http_HeaderCollection_GetHeaders_System_String_" data-uid="Titanium.Web.Proxy.Http.HeaderCollection.GetHeaders(System.String)">GetHeaders(String)</h4>
<div class="markdown level1 summary"><p>Returns all headers with given name if exists
Returns null if does&apos;nt exist</p>
Returns null if doesn&apos;t exist</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
......@@ -135,7 +135,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string AcceptEncoding = &quot;accept-encoding&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string AcceptEncoding = &quot;Accept-Encoding&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -193,7 +193,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string Connection = &quot;connection&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string Connection = &quot;Connection&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -280,7 +280,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string ContentEncoding = &quot;content-encoding&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string ContentEncoding = &quot;Content-Encoding&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -396,7 +396,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string ContentLength = &quot;content-length&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string ContentLength = &quot;Content-Length&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -425,7 +425,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string ContentType = &quot;content-type&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string ContentType = &quot;Content-Type&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -512,7 +512,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string Expect = &quot;expect&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string Expect = &quot;Expect&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -570,7 +570,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string Host = &quot;host&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string Host = &quot;Host&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -773,7 +773,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string TransferEncoding = &quot;transfer-encoding&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string TransferEncoding = &quot;Transfer-Encoding&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -831,7 +831,7 @@
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string Upgrade = &quot;upgrade&quot;</code></pre>
<pre><code class="lang-csharp hljs">public const string Upgrade = &quot;Upgrade&quot;</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
......
......@@ -194,19 +194,19 @@
</h3>
<span class="small pull-right mobile-hide">
<span class="divider">|</span>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Http2_Hpack_Encoder_EncodeHeader_System_IO_BinaryWriter_System_String_System_String_System_Boolean_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Http2.Hpack.Encoder.EncodeHeader(System.IO.BinaryWriter%2CSystem.String%2CSystem.String%2CSystem.Boolean)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Http2_Hpack_Encoder_EncodeHeader_System_IO_BinaryWriter_System_String_System_String_System_Boolean_Titanium_Web_Proxy_Http2_Hpack_HpackUtil_IndexType_System_Boolean_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Http2.Hpack.Encoder.EncodeHeader(System.IO.BinaryWriter%2CSystem.String%2CSystem.String%2CSystem.Boolean%2CTitanium.Web.Proxy.Http2.Hpack.HpackUtil.IndexType%2CSystem.Boolean)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs/#L64">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs/#L66">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Http2_Hpack_Encoder_EncodeHeader_" data-uid="Titanium.Web.Proxy.Http2.Hpack.Encoder.EncodeHeader*"></a>
<h4 id="Titanium_Web_Proxy_Http2_Hpack_Encoder_EncodeHeader_System_IO_BinaryWriter_System_String_System_String_System_Boolean_" data-uid="Titanium.Web.Proxy.Http2.Hpack.Encoder.EncodeHeader(System.IO.BinaryWriter,System.String,System.String,System.Boolean)">EncodeHeader(BinaryWriter, String, String, Boolean)</h4>
<h4 id="Titanium_Web_Proxy_Http2_Hpack_Encoder_EncodeHeader_System_IO_BinaryWriter_System_String_System_String_System_Boolean_Titanium_Web_Proxy_Http2_Hpack_HpackUtil_IndexType_System_Boolean_" data-uid="Titanium.Web.Proxy.Http2.Hpack.Encoder.EncodeHeader(System.IO.BinaryWriter,System.String,System.String,System.Boolean,Titanium.Web.Proxy.Http2.Hpack.HpackUtil.IndexType,System.Boolean)">EncodeHeader(BinaryWriter, String, String, Boolean, HpackUtil.IndexType, Boolean)</h4>
<div class="markdown level1 summary"><p>Encode the header field into the header block.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false)</code></pre>
<pre><code class="lang-csharp hljs">public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false, HpackUtil.IndexType indexType = HpackUtil.IndexType.Incremental, bool useStaticName = true)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -240,6 +240,18 @@
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">sensitive</span></td>
<td><p>If set to <code>true</code> sensitive.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="Titanium.Web.Proxy.Http2.Hpack.HpackUtil.IndexType.html">HpackUtil.IndexType</a></td>
<td><span class="parametername">indexType</span></td>
<td><p>Index type.</p>
</td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">useStaticName</span></td>
<td><p>Use static name.</p>
</td>
</tr>
</tbody>
......@@ -249,7 +261,7 @@
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Http2_Hpack_Encoder_SetMaxHeaderTableSize_System_IO_BinaryWriter_System_Int32_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Http2.Hpack.Encoder.SetMaxHeaderTableSize(System.IO.BinaryWriter%2CSystem.Int32)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs/#L134">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs/#L135">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Http2_Hpack_Encoder_SetMaxHeaderTableSize_" data-uid="Titanium.Web.Proxy.Http2.Hpack.Encoder.SetMaxHeaderTableSize*"></a>
<h4 id="Titanium_Web_Proxy_Http2_Hpack_Encoder_SetMaxHeaderTableSize_System_IO_BinaryWriter_System_Int32_" data-uid="Titanium.Web.Proxy.Http2.Hpack.Encoder.SetMaxHeaderTableSize(System.IO.BinaryWriter,System.Int32)">SetMaxHeaderTableSize(BinaryWriter, Int32)</h4>
......
......@@ -199,7 +199,7 @@ So client application know that it is communicating with a proxy server.</p>
<div class="markdown level1 summary"><p>Intercept tunnel connect request.
Valid only for explicit endpoints.
Set the <a class="xref" href="Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html#Titanium_Web_Proxy_EventArguments_TunnelConnectSessionEventArgs_DecryptSsl">DecryptSsl</a> property to false if this HTTP connect request
should&apos;nt be decrypted and instead be relayed.</p>
shouldn&apos;t be decrypted and instead be relayed.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
......@@ -160,6 +160,48 @@
</tr>
</tbody>
</table>
<span class="small pull-right mobile-hide">
<span class="divider">|</span>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader__ctor_System_String_System_String_System_Boolean_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.%23ctor(System.String%2CSystem.String%2CSystem.Boolean)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L45">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Models_HttpHeader__ctor_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.#ctor*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader__ctor_System_String_System_String_System_Boolean_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.#ctor(System.String,System.String,System.Boolean)">HttpHeader(String, String, Boolean)</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 HttpHeader(string name, string value, bool headerEntry)</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>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">headerEntry</span></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="fields">Fields
</h3>
<span class="small pull-right mobile-hide">
......@@ -201,7 +243,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader_Name.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.Name%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L48">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L55">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Models_HttpHeader_Name_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Name*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_Name" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Name">Name</h4>
......@@ -210,7 +252,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public string Name { get; set; }</code></pre>
<pre><code class="lang-csharp hljs">public string Name { get; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
......@@ -232,7 +274,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader_Size.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.Size%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L55">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L62">View Source</a>
</span>
<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>
......@@ -262,7 +304,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader_Value.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.Value%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L53">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L60">View Source</a>
</span>
<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>
......@@ -295,7 +337,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader_SizeOf_System_String_System_String_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String%2CSystem.String)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L57">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L64">View Source</a>
</span>
<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>
......@@ -347,7 +389,7 @@ The additional 32 octets account for an estimated overhead associated with an en
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Models_HttpHeader_ToString.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Models.HttpHeader.ToString%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L66">View Source</a>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Models/HttpHeader.cs/#L73">View Source</a>
</span>
<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>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Examples.Basic.Helpers
{
/// <summary>
/// Adapated from
/// Adapted from
/// http://stackoverflow.com/questions/13656846/how-to-programmatic-disable-c-sharp-console-applications-quick-edit-mode
/// </summary>
internal static class ConsoleHelper
......
......@@ -32,11 +32,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
if (exception is ProxyHttpException phex)
{
await WriteToConsole(exception.Message + ": " + phex.InnerException?.Message, true);
await writeToConsole(exception.Message + ": " + phex.InnerException?.Message, true);
}
else
{
await WriteToConsole(exception.Message, true);
await writeToConsole(exception.Message, true);
}
};
proxyServer.ForwardToUpstreamGateway = true;
......@@ -52,8 +52,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
public void StartProxy()
{
proxyServer.BeforeRequest += OnRequest;
proxyServer.BeforeResponse += OnResponse;
proxyServer.BeforeRequest += onRequest;
proxyServer.BeforeResponse += onResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
......@@ -63,8 +63,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000);
// Fired when a CONNECT request is received
explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += OnBeforeTunnelConnectResponse;
explicitEndPoint.BeforeTunnelConnectRequest += onBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += onBeforeTunnelConnectResponse;
// An explicit endpoint is where the client knows about the existence of a proxy
// So client sends request in a proxy friendly manner
......@@ -102,11 +102,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
public void Stop()
{
explicitEndPoint.BeforeTunnelConnectRequest -= OnBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse -= OnBeforeTunnelConnectResponse;
explicitEndPoint.BeforeTunnelConnectRequest -= onBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse -= onBeforeTunnelConnectResponse;
proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse;
proxyServer.BeforeRequest -= onRequest;
proxyServer.BeforeResponse -= onResponse;
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;
......@@ -116,10 +116,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
}
private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
await WriteToConsole("Tunnel to: " + hostname);
await writeToConsole("Tunnel to: " + hostname);
if (hostname.Contains("dropbox.com"))
{
......@@ -130,16 +130,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
}
private 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)
private async Task onRequest(object sender, SessionEventArgs e)
{
await WriteToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
await WriteToConsole(e.HttpClient.Request.Url);
await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
await writeToConsole(e.HttpClient.Request.Url);
// store it in the UserData property
// It can be a simple integer, Guid, or any type
......@@ -177,19 +177,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
}
// Modify response
private async Task MultipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
private async Task multipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
{
var session = (SessionEventArgs)sender;
await WriteToConsole("Multipart form data headers:");
await writeToConsole("Multipart form data headers:");
foreach (var header in e.Headers)
{
await WriteToConsole(header.ToString());
await writeToConsole(header.ToString());
}
}
private async Task OnResponse(object sender, SessionEventArgs e)
private async Task onResponse(object sender, SessionEventArgs e)
{
await WriteToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
await writeToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
string ext = System.IO.Path.GetExtension(e.HttpClient.Request.RequestUri.AbsolutePath);
......@@ -261,7 +261,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
return Task.FromResult(0);
}
private async Task WriteToConsole(string message, bool useRedColor = false)
private async Task writeToConsole(string message, bool useRedColor = false)
{
await @lock.WaitAsync();
......
......@@ -36,13 +36,20 @@
</ListView>
<TabControl Grid.Column="2" Grid.Row="0">
<TabItem Header="Session">
<Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox x:Name="TextBoxRequest" Grid.Row="0" />
<TextBox x:Name="TextBoxResponse" Grid.Row="1" />
<TabControl Grid.Row="1">
<TabItem Header="Text">
<TextBox x:Name="TextBoxResponse" />
</TabItem>
<TabItem Header="Image">
<Image x:Name="ImageResponse" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" />
</TabItem>
</TabControl>
</Grid>
</TabItem>
</TabControl>
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
......@@ -8,6 +9,7 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
......@@ -36,6 +38,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public MainWindow()
{
proxyServer = new ProxyServer();
proxyServer.EnableHttp2 = true;
//proxyServer.CertificateManager.CertificateEngine = CertificateEngine.DefaultWindows;
////Set a password for the .pfx file
......@@ -53,6 +58,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer.ForwardToUpstreamGateway = true;
//increase the ThreadPool (for server prod)
//proxyServer.ThreadPoolWorkerThread = Environment.ProcessorCount * 6;
////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
//proxyServer.CertificateManager.EnsureRootCertificate(true);
......@@ -93,7 +101,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
InitializeComponent();
}
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public ObservableCollectionEx<SessionListItem> Sessions { get; } = new ObservableCollectionEx<SessionListItem>();
public SessionListItem SelectedSession
{
......@@ -103,7 +111,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
if (value != selectedSession)
{
selectedSession = value;
SelectedSessionChanged();
selectedSessionChanged();
}
}
}
......@@ -128,7 +136,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
e.DecryptSsl = false;
}
await Dispatcher.InvokeAsync(() => { AddSession(e); });
await Dispatcher.InvokeAsync(() => { addSession(e); });
}
private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
......@@ -144,8 +152,20 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)
{
if (e.HttpClient.ConnectRequest?.TunnelType != TunnelType.Http2)
{
return;
}
SessionListItem item = null;
await Dispatcher.InvokeAsync(() => { item = AddSession(e); });
await Dispatcher.InvokeAsync(() => { item = addSession(e); });
//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//{
//}
//if (!e.HttpClient.Request.RequestUri.ToString().Contains("/mail/u/"))
// return;
if (e.HttpClient.Request.HasBody)
{
......@@ -156,6 +176,11 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
{
if (e.HttpClient.ConnectRequest?.TunnelType != TunnelType.Http2)
{
return;
}
SessionListItem item = null;
await Dispatcher.InvokeAsync(() =>
{
......@@ -165,6 +190,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
});
//e.HttpClient.Response.Headers.AddHeader("X-Titanium-Header", "HTTP/2 works");
//e.SetResponseBody(Encoding.ASCII.GetBytes("TITANIUMMMM!!!!"));
if (item != null)
{
if (e.HttpClient.Response.HasBody)
......@@ -188,15 +217,15 @@ namespace Titanium.Web.Proxy.Examples.Wpf
});
}
private SessionListItem AddSession(SessionEventArgsBase e)
private SessionListItem addSession(SessionEventArgsBase e)
{
var item = CreateSessionListItem(e);
var item = createSessionListItem(e);
Sessions.Add(item);
sessionDictionary.Add(e.HttpClient, item);
return item;
}
private SessionListItem CreateSessionListItem(SessionEventArgsBase e)
private SessionListItem createSessionListItem(SessionEventArgsBase e)
{
lastSessionNumber++;
bool isTunnelConnect = e is TunnelConnectSessionEventArgs;
......@@ -211,18 +240,30 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
e.DataReceived += (sender, args) =>
{
var session = (SessionEventArgs)sender;
var session = (SessionEventArgsBase)sender;
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
{
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
if (tunnelType != TunnelType.Unknown)
{
li.Protocol = TunnelTypeToString(tunnelType);
}
li.ReceivedDataCount += args.Count;
}
};
e.DataSent += (sender, args) =>
{
var session = (SessionEventArgs)sender;
var session = (SessionEventArgsBase)sender;
if (sessionDictionary.TryGetValue(session.HttpClient, out var li))
{
var tunnelType = session.HttpClient.ConnectRequest?.TunnelType ?? TunnelType.Unknown;
if (tunnelType != TunnelType.Unknown)
{
li.Protocol = TunnelTypeToString(tunnelType);
}
li.SentDataCount += args.Count;
}
};
......@@ -232,20 +273,38 @@ namespace Titanium.Web.Proxy.Examples.Wpf
return item;
}
private string TunnelTypeToString(TunnelType tunnelType)
{
switch (tunnelType)
{
case TunnelType.Https:
return "https";
case TunnelType.Websocket:
return "websocket";
case TunnelType.Http2:
return "http2";
}
return null;
}
private void ListViewSessions_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
var selectedItems = ((ListView)sender).SelectedItems;
Sessions.SuppressNotification = true;
foreach (var item in selectedItems.Cast<SessionListItem>().ToArray())
{
Sessions.Remove(item);
sessionDictionary.Remove(item.HttpClient);
}
Sessions.SuppressNotification = false;
}
}
private void SelectedSessionChanged()
private void selectedSessionChanged()
{
if (SelectedSession == null)
{
......@@ -256,7 +315,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
var session = SelectedSession.HttpClient;
var request = session.Request;
var data = (request.IsBodyRead ? request.Body : null) ?? new byte[0];
var fullData = (request.IsBodyRead ? request.Body : null) ?? new byte[0];
var data = fullData;
bool truncated = data.Length > truncateLimit;
if (truncated)
{
......@@ -272,7 +332,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
TextBoxRequest.Text = sb.ToString();
var response = session.Response;
data = (response.IsBodyRead ? response.Body : null) ?? new byte[0];
fullData = (response.IsBodyRead ? response.Body : null) ?? new byte[0];
data = fullData;
truncated = data.Length > truncateLimit;
if (truncated)
{
......@@ -292,6 +353,19 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
TextBoxResponse.Text = sb.ToString();
try
{
using (MemoryStream stream = new MemoryStream(fullData))
{
ImageResponse.Source =
BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
catch
{
ImageResponse.Source = null;
}
}
}
}
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace Titanium.Web.Proxy.Examples.Wpf
{
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
private bool notificationSuppressed;
private bool suppressNotification;
public bool SuppressNotification
{
get => suppressNotification;
set
{
suppressNotification = value;
if (suppressNotification == false && notificationSuppressed)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
notificationSuppressed = false;
}
}
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SuppressNotification)
{
notificationSuppressed = true;
return;
}
base.OnCollectionChanged(e);
}
}
}
\ No newline at end of file
......@@ -73,7 +73,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf.Annotations
}
/// <summary>
/// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
/// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task
/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
/// or of the Lazy.Value property can never be null.
/// </summary>
......@@ -85,7 +85,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf.Annotations
}
/// <summary>
/// Can be appplied to symbols of types derived from IEnumerable as well as to symbols of Task
/// Can be applied to symbols of types derived from IEnumerable as well as to symbols of Task
/// and Lazy classes to indicate that the value of a collection item, of the Task.Result property
/// or of the Lazy.Value property can be null.
/// </summary>
......@@ -251,7 +251,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf.Annotations
/// </list>
/// If method has single input parameter, it's name could be omitted.<br />
/// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same) for method output
/// means that the methos doesn't return normally (throws or terminates the process).<br />
/// means that the method doesn't return normally (throws or terminates the process).<br />
/// Value <c>canbenull</c> is only applicable for output parameters.<br />
/// You can use multiple <c>[ContractAnnotation]</c> for each FDT row, or use single attribute
/// with rows separated by semicolon. There is no notion of order rows, all rows are checked
......
......@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private long? bodySize;
private Exception exception;
private string host;
private string process;
private int processId;
private string protocol;
private long receivedDataCount;
private long sentDataCount;
......@@ -54,10 +54,32 @@ namespace Titanium.Web.Proxy.Examples.Wpf
set => SetField(ref bodySize, value);
}
public int ProcessId
{
get => processId;
set
{
if (SetField(ref processId, value))
{
OnPropertyChanged(nameof(Process));
}
}
}
public string Process
{
get => process;
set => SetField(ref process, value);
get
{
try
{
var process = System.Diagnostics.Process.GetProcessById(processId);
return process.ProcessName + ":" + processId;
}
catch (Exception)
{
return string.Empty;
}
}
}
public long ReceivedDataCount
......@@ -80,13 +102,16 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public event PropertyChangedEventHandler PropertyChanged;
protected void SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!Equals(field, value))
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
[NotifyPropertyChangedInvocator]
......@@ -132,20 +157,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
BodySize = responseSize;
}
Process = GetProcessDescription(HttpClient.ProcessId.Value);
}
private string GetProcessDescription(int processId)
{
try
{
var process = System.Diagnostics.Process.GetProcessById(processId);
return process.ProcessName + ":" + processId;
}
catch (Exception)
{
return string.Empty;
}
ProcessId = HttpClient.ProcessId.Value;
}
}
}
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj" />
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -72,9 +72,6 @@
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="StreamExtended, Version=1.0.201.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\src\packages\StreamExtended.1.0.201\lib\net45\StreamExtended.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
......@@ -95,6 +92,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ObservableCollectionEx.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="SessionListItem.cs" />
<Page Include="MainWindow.xaml">
......@@ -128,7 +126,6 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
......@@ -145,6 +142,10 @@
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\StreamExtended\StreamExtended.csproj">
<Project>{61539dc1-ce80-41e6-a696-8f455ace8d15}</Project>
<Name>StreamExtended</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj">
<Project>{91018b6d-a7a9-45be-9cb3-79cbb8b169a6}</Project>
<Name>Titanium.Web.Proxy</Name>
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StreamExtended" version="1.0.201" targetFramework="net45" />
</packages>
\ No newline at end of file
using System.Collections.Concurrent;
namespace StreamExtended
{
/// <summary>
/// A concrete IBufferPool implementation using a thread-safe stack.
/// Works well when all consumers ask for buffers with the same size.
/// If your application would use variable size buffers consider implementing IBufferPool using System.Buffers library from Microsoft.
/// </summary>
public class DefaultBufferPool : IBufferPool
{
private readonly ConcurrentStack<byte[]> buffers = new ConcurrentStack<byte[]>();
/// <summary>
/// Gets a buffer.
/// </summary>
/// <param name="bufferSize">Size of the buffer.</param>
/// <returns></returns>
public byte[] GetBuffer(int bufferSize)
{
if (!buffers.TryPop(out var buffer) || buffer.Length != bufferSize)
{
buffer = new byte[bufferSize];
}
return buffer;
}
/// <summary>
/// Returns the buffer.
/// </summary>
/// <param name="buffer">The buffer.</param>
public void ReturnBuffer(byte[] buffer)
{
if (buffer != null)
{
buffers.Push(buffer);
}
}
public void Dispose()
{
buffers.Clear();
}
}
}
using System;
namespace StreamExtended
{
/// <summary>
/// Use this interface to implement custom buffer pool.
/// To use the default buffer pool implementation use DefaultBufferPool class.
/// </summary>
public interface IBufferPool : IDisposable
{
byte[] GetBuffer(int bufferSize);
void ReturnBuffer(byte[] buffer);
}
}
using StreamExtended.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StreamExtended
{
/// <summary>
/// Wraps up the client SSL hello information.
/// </summary>
public class ClientHelloInfo
{
private static readonly string[] compressions = {
"null",
"DEFLATE"
};
public int HandshakeVersion { get; set; }
public int MajorVersion { get; set; }
public int MinorVersion { get; set; }
public byte[] Random { get; set; }
public DateTime Time
{
get
{
DateTime time = DateTime.MinValue;
if (Random.Length > 3)
{
time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
.AddSeconds(((uint)Random[3] << 24) + ((uint)Random[2] << 16) + ((uint)Random[1] << 8) + (uint)Random[0]).ToLocalTime();
}
return time;
}
}
public byte[] SessionId { get; set; }
public int[] Ciphers { get; set; }
public byte[] CompressionData { get; set; }
internal int ClientHelloLength { get; set; }
internal int EntensionsStartPosition { get; set; }
public Dictionary<string, SslExtension> Extensions { get; set; }
private static string SslVersionToString(int major, int minor)
{
string str = "Unknown";
if (major == 3 && minor == 3)
str = "TLS/1.2";
else if (major == 3 && minor == 2)
str = "TLS/1.1";
else if (major == 3 && minor == 1)
str = "TLS/1.0";
else if (major == 3 && minor == 0)
str = "SSL/3.0";
else if (major == 2 && minor == 0)
str = "SSL/2.0";
return $"{major}.{minor} ({str})";
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"A SSLv{HandshakeVersion}-compatible ClientHello handshake was found. Titanium extracted the parameters below.");
sb.AppendLine();
sb.AppendLine($"Version: {SslVersionToString(MajorVersion, MinorVersion)}");
sb.AppendLine($"Random: {string.Join(" ", Random.Select(x => x.ToString("X2")))}");
sb.AppendLine($"\"Time\": {Time}");
sb.AppendLine($"SessionID: {string.Join(" ", SessionId.Select(x => x.ToString("X2")))}");
if (Extensions != null)
{
sb.AppendLine("Extensions:");
foreach (var extension in Extensions.Values.OrderBy(x => x.Position))
{
sb.AppendLine($"{extension.Name}: {extension.Data}");
}
}
if (CompressionData != null && CompressionData.Length > 0)
{
int compressionMethod = CompressionData[0];
string compression = compressions.Length > compressionMethod
? compressions[compressionMethod]
: $"unknown [0x{compressionMethod:X2}]";
sb.AppendLine($"Compression: {compression}");
}
if (Ciphers.Length > 0)
{
sb.AppendLine("Ciphers:");
foreach (int cipherSuite in Ciphers)
{
if (!SslCiphers.Ciphers.TryGetValue(cipherSuite, out string cipherStr))
{
cipherStr = "unknown";
}
sb.AppendLine($"[0x{cipherSuite:X4}] {cipherStr}");
}
}
return sb.ToString();
}
}
}
\ No newline at end of file
This diff is collapsed.
namespace StreamExtended.Models
{
/// <summary>
/// The SSL extension information.
/// </summary>
public class SslExtension
{
/// <summary>
/// Gets the value.
/// </summary>
/// <value>
/// The value.
/// </value>
public int Value { get; }
/// <summary>
/// Gets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; }
/// <summary>
/// Gets the data.
/// </summary>
/// <value>
/// The data.
/// </value>
public string Data { get; }
/// <summary>
/// Gets the position.
/// </summary>
/// <value>
/// The position.
/// </value>
public int Position { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SslExtension"/> class.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="name">The name.</param>
/// <param name="data">The data.</param>
/// <param name="position">The position.</param>
public SslExtension(int value, string name, string data, int position)
{
Value = value;
Name = name;
Data = data;
Position = position;
}
}
}
\ No newline at end of file
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace StreamExtended.Network
{
public class ClientHelloAlpnAdderStream : Stream
{
private readonly CustomBufferedStream stream;
private readonly IBufferPool bufferPool;
private bool called;
public ClientHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool)
{
this.stream = stream;
}
public override void Flush()
{
stream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
[DebuggerStepThrough]
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (called)
{
stream.Write(buffer, offset, count);
return;
}
called = true;
var ms = new MemoryStream(buffer, offset, count);
//this can be non async, because reads from a memory stream
var cts = new CancellationTokenSource();
var clientHello = SslTools.PeekClientHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result;
if (clientHello != null)
{
// 0x00 0x10: ALPN identifier
// 0x00 0x0e: length of ALPN data
// 0x00 0x0c: length of ALPN data again:)
var dataToAdd = new byte[]
{
0x0, 0x10, 0x0, 0xE, 0x0, 0xC,
2, (byte)'h', (byte)'2',
8, (byte)'h', (byte)'t', (byte)'t', (byte)'p', (byte)'/', (byte)'1', (byte)'.', (byte)'1'
};
int newByteCount = clientHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length;
var buffer2 = new byte[buffer.Length + newByteCount];
for (int i = 0; i < buffer.Length; i++)
{
buffer2[i] = buffer[i];
}
//this is a hacky solution, but works
int length = (buffer[offset + 3] << 8) + buffer[offset + 4];
length += newByteCount;
buffer2[offset + 3] = (byte)(length >> 8);
buffer2[offset + 4] = (byte)length;
length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8];
length += newByteCount;
buffer2[offset + 6] = (byte)(length >> 16);
buffer2[offset + 7] = (byte)(length >> 8);
buffer2[offset + 8] = (byte)length;
int pos = offset + clientHello.EntensionsStartPosition;
int endPos = offset + clientHello.ClientHelloLength;
if (clientHello.Extensions != null)
{
// update ALPN length
length = (buffer[pos] << 8) + buffer[pos + 1];
length += newByteCount;
buffer2[pos] = (byte)(length >> 8);
buffer2[pos + 1] = (byte)length;
}
else
{
// add ALPN length
length = dataToAdd.Length;
buffer2[pos] = (byte)(length >> 8);
buffer2[pos + 1] = (byte)length;
endPos += 2;
}
for (int i = 0; i < dataToAdd.Length; i++)
{
buffer2[endPos + i] = dataToAdd[i];
}
// copy the reamining data if any
for (int i = clientHello.ClientHelloLength; i < count; i++)
{
buffer2[offset + newByteCount + i] = buffer[offset + i];
}
buffer = buffer2;
count += newByteCount;
}
stream.Write(buffer, offset, count);
}
public override bool CanRead => stream.CanRead;
public override bool CanSeek => stream.CanSeek;
public override bool CanWrite => stream.CanWrite;
public override long Length => stream.Length;
public override long Position
{
get => stream.Position;
set => stream.Position = value;
}
}
}
\ No newline at end of file
using System;
using System.Threading;
using System.Threading.Tasks;
namespace StreamExtended.Network
{
/// <summary>
/// Copies the source stream to destination stream.
/// But this let users to peek and read the copying process.
/// </summary>
public class CopyStream : ICustomStreamReader, IDisposable
{
private readonly ICustomStreamReader reader;
private readonly ICustomStreamWriter writer;
private readonly IBufferPool bufferPool;
public int BufferSize { get; }
private int bufferLength;
private byte[] buffer;
private bool disposed;
public int Available => reader.Available;
public bool DataAvailable => reader.DataAvailable;
public long ReadBytes { get; private set; }
public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool, int bufferSize)
{
this.reader = reader;
this.writer = writer;
BufferSize = bufferSize;
buffer = bufferPool.GetBuffer(bufferSize);
this.bufferPool = bufferPool;
}
public async Task<bool> FillBufferAsync(CancellationToken cancellationToken = default(CancellationToken))
{
await FlushAsync(cancellationToken);
return await reader.FillBufferAsync(cancellationToken);
}
public byte PeekByteFromBuffer(int index)
{
return reader.PeekByteFromBuffer(index);
}
public Task<int> PeekByteAsync(int index, CancellationToken cancellationToken = default(CancellationToken))
{
return reader.PeekByteAsync(index, cancellationToken);
}
public Task<int> PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken = default(CancellationToken))
{
return reader.PeekBytesAsync(buffer, offset, index, size, cancellationToken);
}
public void Flush()
{
//send out the current data from from the buffer
if (bufferLength > 0)
{
writer.Write(buffer, 0, bufferLength);
bufferLength = 0;
}
}
public async Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
{
//send out the current data from from the buffer
if (bufferLength > 0)
{
await writer.WriteAsync(buffer, 0, bufferLength, cancellationToken);
bufferLength = 0;
}
}
public byte ReadByteFromBuffer()
{
byte b = reader.ReadByteFromBuffer();
buffer[bufferLength++] = b;
ReadBytes++;
return b;
}
public int Read(byte[] buffer, int offset, int count)
{
int result = reader.Read(buffer, offset, count);
if (result > 0)
{
if (bufferLength + result > BufferSize)
{
Flush();
}
Buffer.BlockCopy(buffer, offset, this.buffer, bufferLength, result);
bufferLength += result;
ReadBytes += result;
Flush();
}
return result;
}
public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken))
{
int result = await reader.ReadAsync(buffer, offset, count, cancellationToken);
if (result > 0)
{
if (bufferLength + result > BufferSize)
{
await FlushAsync(cancellationToken);
}
Buffer.BlockCopy(buffer, offset, this.buffer, bufferLength, result);
bufferLength += result;
ReadBytes += result;
await FlushAsync(cancellationToken);
}
return result;
}
public Task<string> ReadLineAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return CustomBufferedStream.ReadLineInternalAsync(this, bufferPool, cancellationToken);
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
var b = buffer;
buffer = null;
bufferPool.ReturnBuffer(b);
}
}
}
}
using System.Threading;
using System.Threading.Tasks;
namespace StreamExtended.Network
{
internal class CustomBufferedPeekStream : ICustomStreamReader
{
private readonly IBufferPool bufferPool;
private readonly ICustomStreamReader baseStream;
internal int Position { get; private set; }
internal CustomBufferedPeekStream(ICustomStreamReader baseStream, IBufferPool bufferPool, int startPosition = 0)
{
this.bufferPool = bufferPool;
this.baseStream = baseStream;
Position = startPosition;
}
int ICustomStreamReader.BufferSize => baseStream.BufferSize;
/// <summary>
/// Gets a value indicating whether data is available.
/// </summary>
bool ICustomStreamReader.DataAvailable => Available > 0;
/// <summary>
/// Gets the available data size.
/// </summary>
public int Available => baseStream.Available - Position;
internal async Task<bool> EnsureBufferLength(int length, CancellationToken cancellationToken)
{
var val = await baseStream.PeekByteAsync(Position + length - 1, cancellationToken);
return val != -1;
}
internal byte ReadByte()
{
return baseStream.PeekByteFromBuffer(Position++);
}
internal int ReadInt16()
{
int i1 = ReadByte();
int i2 = ReadByte();
return (i1 << 8) + i2;
}
internal int ReadInt24()
{
int i1 = ReadByte();
int i2 = ReadByte();
int i3 = ReadByte();
return (i1 << 16) + (i2 << 8) + i3;
}
internal byte[] ReadBytes(int length)
{
var buffer = new byte[length];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = ReadByte();
}
return buffer;
}
/// <summary>
/// Fills the buffer asynchronous.
/// </summary>
/// <returns></returns>
Task<bool> ICustomStreamReader.FillBufferAsync(CancellationToken cancellationToken)
{
return baseStream.FillBufferAsync(cancellationToken);
}
/// <summary>
/// Peeks a byte from buffer.
/// </summary>
/// <param name="index">The index.</param>
/// <returns></returns>
byte ICustomStreamReader.PeekByteFromBuffer(int index)
{
return baseStream.PeekByteFromBuffer(index);
}
/// <summary>
/// Peeks bytes asynchronous.
/// </summary>
/// <param name="buffer">The buffer to copy.</param>
/// <param name="offset">The offset where copying.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<int> ICustomStreamReader.PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken)
{
return baseStream.PeekBytesAsync(buffer, offset, index, size, cancellationToken);
}
/// <summary>
/// Peeks a byte asynchronous.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<int> ICustomStreamReader.PeekByteAsync(int index, CancellationToken cancellationToken)
{
return baseStream.PeekByteAsync(index, cancellationToken);
}
/// <summary>
/// Reads a byte from buffer.
/// </summary>
/// <returns></returns>
/// <exception cref="Exception">Buffer is empty</exception>
byte ICustomStreamReader.ReadByteFromBuffer()
{
return ReadByte();
}
int ICustomStreamReader.Read(byte[] buffer, int offset, int count)
{
return baseStream.Read(buffer, offset, count);
}
/// <summary>
/// Reads the asynchronous.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset.</param>
/// <param name="count">The count.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<int> ICustomStreamReader.ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return baseStream.ReadAsync(buffer, offset, count, cancellationToken);
}
/// <summary>
/// Read a line from the byte stream
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<string> ICustomStreamReader.ReadLineAsync(CancellationToken cancellationToken)
{
return CustomBufferedStream.ReadLineInternalAsync(this, bufferPool, cancellationToken);
}
}
}
This diff is collapsed.
using System;
namespace StreamExtended.Network
{
/// <summary>
/// Wraps the data sent/received event argument.
/// </summary>
public class DataEventArgs : EventArgs
{
public DataEventArgs(byte[] buffer, int offset, int count)
{
Buffer = buffer;
Offset = offset;
Count = count;
}
/// <summary>
/// The buffer with data.
/// </summary>
public byte[] Buffer { get; }
/// <summary>
/// Offset in buffer from which valid data begins.
/// </summary>
public int Offset { get; }
/// <summary>
/// Length from offset in buffer with valid data.
/// </summary>
public int Count { get; }
}
}
using System;
using System.Threading;
using System.Threading.Tasks;
namespace StreamExtended.Network
{
/// <summary>
/// This concrete implemetation of interface acts as the source stream for CopyStream class.
/// </summary>
public interface ICustomStreamReader
{
int BufferSize { get; }
int Available { get; }
bool DataAvailable { get; }
/// <summary>
/// Fills the buffer asynchronous.
/// </summary>
/// <returns></returns>
Task<bool> FillBufferAsync(CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Peeks a byte from buffer.
/// </summary>
/// <param name="index">The index.</param>
/// <returns></returns>
/// <exception cref="Exception">Index is out of buffer size</exception>
byte PeekByteFromBuffer(int index);
/// <summary>
/// Peeks a byte asynchronous.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<int> PeekByteAsync(int index, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Peeks bytes asynchronous.
/// </summary>
/// <param name="buffer">The buffer to copy.</param>
/// <param name="offset">The offset where copying.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
Task<int> PeekBytesAsync(byte[] buffer, int offset, int index, int size, CancellationToken cancellationToken = default(CancellationToken));
byte ReadByteFromBuffer();
/// <summary>
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between <paramref name="offset" /> and (<paramref name="offset" /> + <paramref name="count" /> - 1) replaced by the bytes read from the current source.</param>
/// <param name="offset">The zero-based byte offset in <paramref name="buffer" /> at which to begin storing the data read from the current stream.</param>
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
/// <returns>
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
/// </returns>
int Read(byte[] buffer, int offset, int count);
/// <summary>
/// Read the specified number (or less) of raw bytes from the base stream to the given buffer to the specified offset
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="bytesToRead"></param>
/// <param name="cancellationToken"></param>
/// <returns>The number of bytes read</returns>
Task<int> ReadAsync(byte[] buffer, int offset, int bytesToRead,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Read a line from the byte stream
/// </summary>
/// <returns></returns>
Task<string> ReadLineAsync(CancellationToken cancellationToken = default(CancellationToken));
}
}
\ No newline at end of file
using System.Threading;
using System.Threading.Tasks;
namespace StreamExtended.Network
{
/// <summary>
/// A concrete implementation of this interface is required when calling CopyStream.
/// </summary>
public interface ICustomStreamWriter
{
void Write(byte[] buffer, int i, int bufferLength);
Task WriteAsync(byte[] buffer, int i, int bufferLength, CancellationToken cancellationToken);
}
}
\ No newline at end of file
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace StreamExtended.Network
{
public class ServerHelloAlpnAdderStream : Stream
{
private readonly IBufferPool bufferPool;
private readonly CustomBufferedStream stream;
private bool called;
public ServerHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool)
{
this.bufferPool = bufferPool;
this.stream = stream;
}
public override void Flush()
{
stream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
[DebuggerStepThrough]
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (called)
{
stream.Write(buffer, offset, count);
return;
}
called = true;
var ms = new MemoryStream(buffer, offset, count);
//this can be non async, because reads from a memory stream
var cts = new CancellationTokenSource();
var serverHello = SslTools.PeekServerHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result;
if (serverHello != null)
{
// 0x00 0x10: ALPN identifier
// 0x00 0x0e: length of ALPN data
// 0x00 0x0c: length of ALPN data again:)
var dataToAdd = new byte[]
{
0x0, 0x10, 0x0, 0x5, 0x0, 0x3,
2, (byte)'h', (byte)'2'
};
int newByteCount = serverHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length;
var buffer2 = new byte[buffer.Length + newByteCount];
for (int i = 0; i < buffer.Length; i++)
{
buffer2[i] = buffer[i];
}
//this is a hacky solution, but works
int length = (buffer[offset + 3] << 8) + buffer[offset + 4];
length += newByteCount;
buffer2[offset + 3] = (byte)(length >> 8);
buffer2[offset + 4] = (byte)length;
length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8];
length += newByteCount;
buffer2[offset + 6] = (byte)(length >> 16);
buffer2[offset + 7] = (byte)(length >> 8);
buffer2[offset + 8] = (byte)length;
int pos = offset + serverHello.EntensionsStartPosition;
int endPos = offset + serverHello.ServerHelloLength;
if (serverHello.Extensions != null)
{
// update ALPN length
length = (buffer[pos] << 8) + buffer[pos + 1];
length += newByteCount;
buffer2[pos] = (byte)(length >> 8);
buffer2[pos + 1] = (byte)length;
}
else
{
// add ALPN length
length = dataToAdd.Length;
buffer2[pos] = (byte)(length >> 8);
buffer2[pos + 1] = (byte)length;
endPos += 2;
}
for (int i = 0; i < dataToAdd.Length; i++)
{
buffer2[endPos + i] = dataToAdd[i];
}
// copy the reamining data if any
for (int i = serverHello.ServerHelloLength; i < count; i++)
{
buffer2[offset + newByteCount + i] = buffer[offset + i];
}
buffer = buffer2;
count += newByteCount;
}
stream.Write(buffer, offset, count);
}
public override bool CanRead => stream.CanRead;
public override bool CanSeek => stream.CanSeek;
public override bool CanWrite => stream.CanWrite;
public override long Length => stream.Length;
public override long Position
{
get => stream.Position;
set => stream.Position = value;
}
}
}
\ No newline at end of file
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("StreamExtended.Properties")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("StreamExtended.Properties")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5036e0b7-a0d0-4070-8eb0-72c129dee9a3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.1")]
[assembly: AssemblyFileVersion("1.0.1")]
using StreamExtended.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StreamExtended
{
/// <summary>
/// Wraps up the server SSL hello information.
/// </summary>
public class ServerHelloInfo
{
private static readonly string[] compressions = {
"null",
"DEFLATE"
};
public int HandshakeVersion { get; set; }
public int MajorVersion { get; set; }
public int MinorVersion { get; set; }
public byte[] Random { get; set; }
public DateTime Time
{
get
{
DateTime time = DateTime.MinValue;
if (Random.Length > 3)
{
time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)
.AddSeconds(((uint)Random[3] << 24) + ((uint)Random[2] << 16) + ((uint)Random[1] << 8) + (uint)Random[0]).ToLocalTime();
}
return time;
}
}
public byte[] SessionId { get; set; }
public int CipherSuite { get; set; }
public byte CompressionMethod { get; set; }
internal int ServerHelloLength { get; set; }
internal int EntensionsStartPosition { get; set; }
public Dictionary<string, SslExtension> Extensions { get; set; }
private static string SslVersionToString(int major, int minor)
{
string str = "Unknown";
if (major == 3 && minor == 3)
str = "TLS/1.2";
else if (major == 3 && minor == 2)
str = "TLS/1.1";
else if (major == 3 && minor == 1)
str = "TLS/1.0";
else if (major == 3 && minor == 0)
str = "SSL/3.0";
else if (major == 2 && minor == 0)
str = "SSL/2.0";
return $"{major}.{minor} ({str})";
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"A SSLv{HandshakeVersion}-compatible ServerHello handshake was found. Titanium extracted the parameters below.");
sb.AppendLine();
sb.AppendLine($"Version: {SslVersionToString(MajorVersion, MinorVersion)}");
sb.AppendLine($"Random: {string.Join(" ", Random.Select(x => x.ToString("X2")))}");
sb.AppendLine($"\"Time\": {Time}");
sb.AppendLine($"SessionID: {string.Join(" ", SessionId.Select(x => x.ToString("X2")))}");
if (Extensions != null)
{
sb.AppendLine("Extensions:");
foreach (var extension in Extensions.Values.OrderBy(x => x.Position))
{
sb.AppendLine($"{extension.Name}: {extension.Data}");
}
}
string compression = compressions.Length > CompressionMethod
? compressions[CompressionMethod]
: $"unknown [0x{CompressionMethod:X2}]";
sb.AppendLine($"Compression: {compression}");
sb.Append("Cipher:");
if (!SslCiphers.Ciphers.TryGetValue(CipherSuite, out string cipherStr))
{
cipherStr = "unknown";
}
sb.AppendLine($"[0x{CipherSuite:X4}] {cipherStr}");
return sb.ToString();
}
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>StrongKey.snk</AssemblyOriginatorKeyFile>
<Version>1.0.0</Version>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Description>Package Description</Description>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Network\ClientHelloAlpnAdderStream.cs" />
<Compile Remove="Network\ServerHelloAlpnAdderStream.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="StreamExtended.nuspec" />
</ItemGroup>
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace StreamExtended
{
/// <summary>
/// Mimic a Task but you can set AsyncState
/// </summary>
/// <typeparam name="T"></typeparam>
public class TaskResult : IAsyncResult
{
Task Task;
object mAsyncState;
public TaskResult(Task pTask, object state)
{
Task = pTask;
mAsyncState = state;
}
public object AsyncState => mAsyncState;
public WaitHandle AsyncWaitHandle => ((IAsyncResult)Task).AsyncWaitHandle;
public bool CompletedSynchronously => ((IAsyncResult)Task).CompletedSynchronously;
public bool IsCompleted => Task.IsCompleted;
public void GetResult() { this.Task.GetAwaiter().GetResult(); }
}
/// <summary>
/// Mimic a Task<T> but you can set AsyncState
/// </summary>
/// <typeparam name="T"></typeparam>
public class TaskResult<T> : IAsyncResult
{
Task<T> Task;
object mAsyncState;
public TaskResult(Task<T> pTask, object state)
{
Task = pTask;
mAsyncState = state;
}
public object AsyncState => mAsyncState;
public WaitHandle AsyncWaitHandle => ((IAsyncResult)Task).AsyncWaitHandle;
public bool CompletedSynchronously => ((IAsyncResult)Task).CompletedSynchronously;
public bool IsCompleted => Task.IsCompleted;
public T Result => Task.Result;
}
}
......@@ -23,7 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC1E0789
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.UnitTests", "..\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.UnitTests", "..\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.Examples.Basic", "..\examples\Titanium.Web.Proxy.Examples.Basic\Titanium.Web.Proxy.Examples.Basic.csproj", "{1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}"
EndProject
......@@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.IntegrationTests", "..\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{1D053D72-DCB4-4517-ACDD-D35ADC186950}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StreamExtended", "StreamExtended\StreamExtended.csproj", "{61539DC1-CE80-41E6-A696-8F455ACE8D15}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
......@@ -79,6 +81,14 @@ Global
{1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|Any CPU.Build.0 = Release|Any CPU
{1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.ActiveCfg = Release|Any CPU
{1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.Build.0 = Release|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Debug|x64.ActiveCfg = Debug|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Debug|x64.Build.0 = Debug|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Release|Any CPU.Build.0 = Release|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Release|x64.ActiveCfg = Release|Any CPU
{61539DC1-CE80-41E6-A696-8F455ACE8D15}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -90,7 +100,7 @@ Global
{1D053D72-DCB4-4517-ACDD-D35ADC186950} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A}
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A}
EndGlobalSection
EndGlobal
......@@ -19,16 +19,19 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MTA/@EntryIndexedValue">MTA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OID/@EntryIndexedValue">OID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OIDS/@EntryIndexedValue">OIDS</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<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/PredefinedNamingRules/=PublicFields/@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>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
......
......@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.EventArguments
public X509Certificate RemoteCertificate { get; internal set; }
/// <summary>
/// Acceptable issuers as listed by remoted server.
/// Acceptable issuers as listed by remote server.
/// </summary>
public string[] AcceptableIssuers { get; internal set; }
......
......@@ -4,6 +4,7 @@ using System.IO;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Exceptions;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -60,7 +61,11 @@ namespace Titanium.Web.Proxy.EventArguments
chunkHead = chunkHead.Substring(0, idx);
}
int chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);
if (!int.TryParse(chunkHead, NumberStyles.HexNumber, null, out int chunkSize))
{
throw new ProxyHttpException($"Invalid chunk length: '{chunkHead}'", null, null);
}
bytesRemaining = chunkSize;
if (chunkSize == 0)
......
......@@ -31,12 +31,12 @@ namespace Titanium.Web.Proxy.EventArguments
public bool DenyConnect { get; set; }
/// <summary>
/// Is this a connect request to secure HTTP server? Or is it to someother protocol.
/// Is this a connect request to secure HTTP server? Or is it to some other protocol.
/// </summary>
public bool IsHttpsConnect
{
get => isHttpsConnect ??
throw new Exception("The value of this property is known in the BeforeTunnectConnectResponse event");
throw new Exception("The value of this property is known in the BeforeTunnelConnectResponse event");
internal set => isHttpsConnect = value;
}
......
......@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Exceptions
/// Initializes a new instance of the <see cref="ProxyException" /> class.
/// - must be invoked by derived classes' constructors
/// </summary>
/// <param name="message">Excception message</param>
/// <param name="message">Exception message</param>
/// <param name="innerException">Inner exception associated</param>
protected ProxyException(string message, Exception innerException) : base(message, innerException)
{
......
......@@ -17,6 +17,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="input"></param>
/// <param name="output"></param>
/// <param name="onCopy"></param>
/// <param name="bufferPool"></param>
/// <param name="bufferSize"></param>
internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
IBufferPool bufferPool, int bufferSize)
......@@ -30,6 +31,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="input"></param>
/// <param name="output"></param>
/// <param name="onCopy"></param>
/// <param name="bufferPool"></param>
/// <param name="bufferSize"></param>
/// <param name="cancellationToken"></param>
internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
//
//
// Mono.Security.BitConverterLE.cs
// Like System.BitConverter but always little endian
//
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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