Unverified Commit 8b890fe3 authored by honfika's avatar honfika Committed by GitHub

Merge pull request #613 from justcoding121/beta

Beta to stable
parents 4d635967 d58edd61
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 master branch
- [ ] Branching - If this is not a hotfix, I am making this request against the master branch
## 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)
......@@ -36,7 +38,7 @@ Supports
#### Windows
* Visual Studio Code as IDE for .NET core
* Visual Studio 2017 as IDE for .NET framework/.NET core
* Visual Studio 2017/2019 as IDE for .NET framework/.NET core
#### Mac OS
* Visual Studio Code as IDE for .NET core
......
......@@ -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
......
......@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Demo")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......
......@@ -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
......
......@@ -10,7 +10,7 @@ using System.Windows;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Demo WPF")]
[assembly: AssemblyCopyright("Copyright ©2017 Titanium")]
[assembly: AssemblyCopyright("Copyright © Titanium 2015-2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......
......@@ -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.190.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\src\packages\StreamExtended.1.0.190\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>
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StreamExtended" version="1.0.190" targetFramework="net45" />
</packages>
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26906.1
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{B6DBABDC-C985-4872-9C38-B4E5079CBC4B}"
EndProject
......@@ -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
......
......@@ -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; }
......
......@@ -2,8 +2,9 @@
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
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)
......
......@@ -4,12 +4,12 @@ using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -28,6 +28,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
private bool reRequest;
/// <summary>
/// Is this session a HTTP/2 promise?
/// </summary>
public bool IsPromise { get; internal set; }
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
......@@ -89,13 +94,35 @@ namespace Titanium.Web.Proxy.EventArguments
// If not already read (not cached yet)
if (!request.IsBodyRead)
{
var body = await readBodyAsync(true, cancellationToken);
request.Body = body;
if (request.HttpVersion == HttpHeader.Version20)
{
// do not send to the remote endpoint
request.Http2IgnoreBodyFrames = true;
request.Http2BodyData = new MemoryStream();
var tcs = new TaskCompletionSource<bool>();
request.ReadHttp2BodyTaskCompletionSource = tcs;
// signal to HTTP/2 copy frame method to continue
request.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true);
await tcs.Task;
// Now set the flag to true
// So that next time we can deliver body from cache
request.IsBodyRead = true;
}
else
{
var body = await readBodyAsync(true, cancellationToken);
request.Body = body;
// Now set the flag to true
// So that next time we can deliver body from cache
request.IsBodyRead = true;
OnDataSent(body, 0, body.Length);
// Now set the flag to true
// So that next time we can deliver body from cache
request.IsBodyRead = true;
OnDataSent(body, 0, body.Length);
}
}
}
......@@ -117,7 +144,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));
}
}
......@@ -140,13 +167,35 @@ namespace Titanium.Web.Proxy.EventArguments
// If not already read (not cached yet)
if (!response.IsBodyRead)
{
var body = await readBodyAsync(false, cancellationToken);
response.Body = body;
if (response.HttpVersion == HttpHeader.Version20)
{
// do not send to the remote endpoint
response.Http2IgnoreBodyFrames = true;
response.Http2BodyData = new MemoryStream();
var tcs = new TaskCompletionSource<bool>();
response.ReadHttp2BodyTaskCompletionSource = tcs;
// signal to HTTP/2 copy frame method to continue
response.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true);
await tcs.Task;
// Now set the flag to true
// So that next time we can deliver body from cache
response.IsBodyRead = true;
OnDataReceived(body, 0, body.Length);
// Now set the flag to true
// So that next time we can deliver body from cache
response.IsBodyRead = true;
}
else
{
var body = await readBodyAsync(false, cancellationToken);
response.Body = body;
// Now set the flag to true
// So that next time we can deliver body from cache
response.IsBodyRead = true;
OnDataReceived(body, 0, body.Length);
}
}
}
......@@ -154,7 +203,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize);
var writer = new HttpWriter(bodyStream, BufferPool, BufferSize);
if (isRequest)
{
......@@ -186,7 +235,7 @@ namespace Titanium.Web.Proxy.EventArguments
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize);
var writer = new HttpWriter(bodyStream, BufferPool, BufferSize);
await copyBodyAsync(isRequest, true, writer, TransformationMode.None, null, cancellationToken);
}
}
......@@ -207,7 +256,7 @@ namespace Titanium.Web.Proxy.EventArguments
var reader = getStreamReader(true);
string boundary = HttpHelper.GetBoundaryFromContentType(request.ContentType);
using (var copyStream = new CopyStream(reader, writer, bufferPool, bufferSize))
using (var copyStream = new CopyStream(reader, writer, BufferPool, BufferSize))
{
while (contentLength > copyStream.ReadBytes)
{
......@@ -259,7 +308,7 @@ namespace Titanium.Web.Proxy.EventArguments
string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength);
Stream s = limitedStream = new LimitedStream(stream, BufferPool, isChunked, contentLength);
if (transformation == TransformationMode.Uncompress && contentEncoding != null)
{
......@@ -268,7 +317,7 @@ namespace Titanium.Web.Proxy.EventArguments
try
{
using (var bufStream = new CustomBufferedStream(s, bufferPool, bufferSize, true))
using (var bufStream = new CustomBufferedStream(s, BufferPool, BufferSize, true))
{
await writer.CopyBodyAsync(bufStream, false, -1, onCopy, cancellationToken);
}
......@@ -290,7 +339,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
int bufferDataLength = 0;
var buffer = bufferPool.GetBuffer(bufferSize);
var buffer = BufferPool.GetBuffer(BufferSize);
try
{
int boundaryLength = boundary.Length + 4;
......@@ -340,7 +389,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
finally
{
bufferPool.ReturnBuffer(buffer);
BufferPool.ReturnBuffer(buffer);
}
}
......
......@@ -2,13 +2,13 @@
using System.Collections.Generic;
using System.Net;
using System.Threading;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -24,14 +24,14 @@ namespace Titanium.Web.Proxy.EventArguments
internal TcpServerConnection ServerConnection => HttpClient.Connection;
internal TcpClientConnection ClientConnection => ProxyClient.Connection;
protected readonly int bufferSize;
protected readonly IBufferPool bufferPool;
protected readonly ExceptionHandler exceptionFunc;
protected readonly int BufferSize;
protected readonly IBufferPool BufferPool;
protected readonly ExceptionHandler ExceptionFunc;
/// <summary>
/// Relative milliseconds for various events.
/// </summary>
public Dictionary<string, DateTime> TimeLine { get; set; } = new Dictionary<string, DateTime>();
public Dictionary<string, DateTime> TimeLine { get; } = new Dictionary<string, DateTime>();
/// <summary>
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
......@@ -39,9 +39,9 @@ namespace Titanium.Web.Proxy.EventArguments
private SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource)
{
bufferSize = server.BufferSize;
bufferPool = server.BufferPool;
exceptionFunc = server.ExceptionFunc;
BufferSize = server.BufferSize;
BufferPool = server.BufferPool;
ExceptionFunc = server.ExceptionFunc;
TimeLine["Session Created"] = DateTime.Now;
}
......@@ -55,25 +55,7 @@ namespace Titanium.Web.Proxy.EventArguments
HttpClient = new HttpWebClient(request);
LocalEndPoint = endPoint;
HttpClient.ProcessId = new Lazy<int>(() =>
{
if (RunTime.IsWindows)
{
var remoteEndPoint = ClientEndPoint;
// If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
var ipVersion = endPoint.IpV6Enabled ? IpVersion.Ipv6 : IpVersion.Ipv4;
return TcpHelper.GetProcessIdByLocalPort(ipVersion, remoteEndPoint.Port);
}
// can't access process Id of remote request from remote machine
return -1;
}
throw new PlatformNotSupportedException();
});
HttpClient.ProcessId = new Lazy<int>(() => ProxyClient.Connection.GetProcessId(endPoint));
}
/// <summary>
......@@ -161,7 +143,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));
}
}
......@@ -173,7 +155,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));
}
}
......
......@@ -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)
{
......
......@@ -5,7 +5,7 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.StreamExtended;
namespace Titanium.Web.Proxy.Extensions
{
......
......@@ -2,7 +2,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
namespace Titanium.Web.Proxy.Extensions
{
......@@ -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,
......
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Helpers
{
......@@ -120,9 +123,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader)
internal static Task<int> IsConnectMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken = default)
{
return startsWith(clientStreamReader, "CONNECT");
return startsWith(clientStreamReader, bufferPool, bufferSize, "CONNECT", cancellationToken);
}
/// <summary>
......@@ -130,9 +133,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader)
internal static Task<int> IsPriMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken = default)
{
return startsWith(clientStreamReader, "PRI");
return startsWith(clientStreamReader, bufferPool, bufferSize, "PRI", cancellationToken);
}
/// <summary>
......@@ -143,37 +146,47 @@ 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, IBufferPool bufferPool, int bufferSize, string expectedStart, CancellationToken cancellationToken = default)
{
bool isExpected = true;
int legthToCheck = 10;
for (int i = 0; i < legthToCheck; i++)
int iRet = -1;
const int lengthToCheck = 10;
byte[] buffer = null;
try
{
int b = await clientStreamReader.PeekByteAsync(i);
if (b == -1)
{
return -1;
}
buffer = bufferPool.GetBuffer(Math.Max(bufferSize, lengthToCheck));
if (b == ' ' && i > 2)
{
return isExpected ? 1 : 0;
}
int peeked = await clientStreamReader.PeekBytesAsync(buffer, 0, 0, lengthToCheck, cancellationToken);
char ch = (char)b;
if (!char.IsLetter(ch))
if (peeked > 0)
{
return -1;
}
bool isExpected = true;
if (i >= expectedStart.Length || ch != expectedStart[i])
{
isExpected = false;
for (int i = 0; i < lengthToCheck; i++)
{
int b = buffer[i];
if (b == ' ' && i > 2)
return isExpected ? 1 : 0;
else
{
char ch = (char)b;
if (!char.IsLetter(ch))
return -1;
else if (i >= expectedStart.Length || ch != expectedStart[i])
isExpected = false;
}
}
// only letters
iRet = isExpected ? 1 : 0;
}
}
// only letters
return isExpected ? 1 : 0;
finally
{
bufferPool.ReturnBuffer(buffer);
buffer = null;
}
return iRet;
}
}
}
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
namespace Titanium.Web.Proxy.Helpers
{
......@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy.Helpers
internal async Task WriteRequestAsync(Request request, bool flush = true,
CancellationToken cancellationToken = default)
{
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.OriginalUrl, request.HttpVersion),
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.RequestUriString, request.HttpVersion),
cancellationToken);
await WriteAsync(request, flush, cancellationToken);
}
......
......@@ -2,8 +2,8 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
namespace Titanium.Web.Proxy.Helpers
{
......
......@@ -4,10 +4,10 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Helpers
{
......@@ -18,18 +18,13 @@ namespace Titanium.Web.Proxy.Helpers
private static readonly byte[] newLine = ProxyConstants.NewLineBytes;
private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();
private readonly char[] charBuffer;
private static readonly Encoding encoder = Encoding.ASCII;
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];
}
internal int BufferSize { get; }
......@@ -55,12 +50,10 @@ namespace Titanium.Web.Proxy.Helpers
int charCount = value.Length;
if (charCount < BufferSize - newLineChars)
{
value.CopyTo(0, charBuffer, 0, charCount);
var buffer = bufferPool.GetBuffer(BufferSize);
try
{
int idx = encoder.GetBytes(charBuffer, 0, charCount, buffer, 0, true);
int idx = encoder.GetBytes(value, 0, charCount, buffer, 0);
if (newLineChars > 0)
{
Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
......@@ -76,11 +69,8 @@ namespace Titanium.Web.Proxy.Helpers
}
else
{
var charBuffer = new char[charCount];
value.CopyTo(0, charBuffer, 0, charCount);
var buffer = new byte[charCount + newLineChars + 1];
int idx = encoder.GetBytes(charBuffer, 0, charCount, buffer, 0, true);
int idx = encoder.GetBytes(value, 0, charCount, buffer, 0);
if (newLineChars > 0)
{
Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
......
namespace Titanium.Web.Proxy.Helpers
{
internal class Ref<T>
{
internal Ref()
{
}
internal Ref(T value)
{
Value = value;
}
internal T Value { get; set; }
public override string ToString()
{
var value = Value;
return value == null ? string.Empty : value.ToString();
}
public static implicit operator T(Ref<T> r)
{
return r.Value;
}
public static implicit operator Ref<T>(T value)
{
return new Ref<T>(value);
}
}
}
......@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Helpers
internal static bool IsRunningAsUwp()
{
if (IsWindows7OrLower)
if (isWindows7OrLower)
{
return false;
}
......@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Helpers
}
}
private static bool IsWindows7OrLower
private static bool isWindows7OrLower
{
get
{
......
......@@ -80,7 +80,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="protocolType"></param>
internal void SetProxy(string hostname, int port, ProxyProtocolType protocolType)
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
internal void RemoveProxy(ProxyProtocolType protocolType, bool saveOriginalConfig = true)
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -168,7 +168,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
internal void DisableAllProxy()
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy.Helpers
internal void SetAutoProxyUrl(string url)
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -201,7 +201,7 @@ namespace Titanium.Web.Proxy.Helpers
internal void SetProxyOverride(string proxyOverride)
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -286,7 +286,7 @@ namespace Titanium.Web.Proxy.Helpers
internal ProxyInfo GetProxyInfoFromRegistry()
{
using (var reg = OpenInternetSettingsKey())
using (var reg = openInternetSettingsKey())
{
if (reg == null)
{
......@@ -347,7 +347,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary>
/// Opens the registry key with the internet settings
/// </summary>
private static RegistryKey OpenInternetSettingsKey()
private static RegistryKey openInternetSettingsKey()
{
return Registry.CurrentUser.OpenSubKey(regKeyInternetSettings, true);
}
......
using System;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
namespace Titanium.Web.Proxy.Helpers
{
......@@ -96,11 +96,12 @@ namespace Titanium.Web.Proxy.Helpers
/// <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
/// Useful for websocket requests
/// Task-based Asynchronous Pattern
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferPool"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
......@@ -128,10 +129,11 @@ namespace Titanium.Web.Proxy.Helpers
/// <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
/// Useful for websocket requests
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferPool"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
......
using StreamExtended;
using Titanium.Web.Proxy.StreamExtended;
namespace Titanium.Web.Proxy.Http
{
......@@ -12,6 +12,8 @@ namespace Titanium.Web.Proxy.Http
Method = "CONNECT";
}
public TunnelType TunnelType { get; internal set; }
public ClientHelloInfo ClientHelloInfo { get; set; }
}
}
using System;
using System.Net;
using StreamExtended;
using Titanium.Web.Proxy.StreamExtended;
namespace Titanium.Web.Proxy.Http
{
......@@ -12,11 +12,11 @@ namespace Titanium.Web.Proxy.Http
public ServerHelloInfo ServerHelloInfo { get; set; }
/// <summary>
/// Creates a successfull CONNECT response
/// Creates a successful CONNECT response
/// </summary>
/// <param name="httpVersion"></param>
/// <returns></returns>
internal static ConnectResponse CreateSuccessfullConnectResponse(Version httpVersion)
internal static ConnectResponse CreateSuccessfulConnectResponse(Version httpVersion)
{
var response = new ConnectResponse
{
......
......@@ -67,7 +67,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Returns all headers with given name if exists
/// Returns null if does'nt exist
/// Returns null if doesn't exist
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
......
using System;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Http
{
......
......@@ -97,10 +97,19 @@ namespace Titanium.Web.Proxy.Http
var writer = Connection.StreamWriter;
string url;
if (useUpstreamProxy || isTransparent)
{
url = Request.RequestUriString;
}
else
{
var uri = Request.RequestUri;
url = uri.IsWellFormedOriginalString() ? uri.PathAndQuery : uri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
}
// prepare the request & headers
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
Request.HttpVersion), cancellationToken);
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, url, Request.HttpVersion), cancellationToken);
var headerBuilder = new StringBuilder();
......
......@@ -6,28 +6,28 @@
public static class KnownHeaders
{
// Both
public const string Connection = "connection";
public const string Connection = "Connection";
public const string ConnectionClose = "close";
public const string ConnectionKeepAlive = "keep-alive";
public const string ContentLength = "content-length";
public const string ContentLength = "Content-Length";
public const string ContentType = "content-type";
public const string ContentType = "Content-Type";
public const string ContentTypeCharset = "charset";
public const string ContentTypeBoundary = "boundary";
public const string Upgrade = "upgrade";
public const string Upgrade = "Upgrade";
public const string UpgradeWebsocket = "websocket";
// Request headers
public const string AcceptEncoding = "accept-encoding";
public const string AcceptEncoding = "Accept-Encoding";
public const string Authorization = "Authorization";
public const string Expect = "expect";
public const string Expect = "Expect";
public const string Expect100Continue = "100-continue";
public const string Host = "host";
public const string Host = "Host";
public const string ProxyAuthorization = "Proxy-Authorization";
public const string ProxyAuthorizationBasic = "basic";
......@@ -36,7 +36,7 @@
public const string ProxyConnectionClose = "close";
// Response headers
public const string ContentEncoding = "content-encoding";
public const string ContentEncoding = "Content-Encoding";
public const string ContentEncodingDeflate = "deflate";
public const string ContentEncodingGzip = "gzip";
public const string ContentEncodingBrotli = "br";
......@@ -45,7 +45,7 @@
public const string ProxyAuthenticate = "Proxy-Authenticate";
public const string TransferEncoding = "transfer-encoding";
public const string TransferEncoding = "Transfer-Encoding";
public const string TransferEncodingChunked = "chunked";
}
}
......@@ -14,6 +14,8 @@ namespace Titanium.Web.Proxy.Http
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Request : RequestResponseBase
{
private string originalUrl;
/// <summary>
/// Request Method.
/// </summary>
......@@ -32,7 +34,20 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// The original request Url.
/// </summary>
public string OriginalUrl { get; set; }
public string OriginalUrl
{
get => originalUrl;
internal set
{
originalUrl = value;
RequestUriString = value;
}
}
/// <summary>
/// The request uri as it is in the HTTP header
/// </summary>
public string RequestUriString { get; set; }
/// <summary>
/// Has request body?
......@@ -140,7 +155,7 @@ namespace Titanium.Web.Proxy.Http
get
{
var sb = new StringBuilder();
sb.Append($"{CreateRequestLine(Method, OriginalUrl, HttpVersion)}{ProxyConstants.NewLine}");
sb.Append($"{CreateRequestLine(Method, RequestUriString, HttpVersion)}{ProxyConstants.NewLine}");
foreach (var header in Headers)
{
sb.Append($"{header.ToString()}{ProxyConstants.NewLine}");
......
......@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
......@@ -49,6 +50,21 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
internal string OriginalContentEncoding { get; set; }
internal TaskCompletionSource<bool> ReadHttp2BeforeHandlerTaskCompletionSource;
internal TaskCompletionSource<bool> ReadHttp2BodyTaskCompletionSource;
internal MemoryStream Http2BodyData;
internal bool Http2IgnoreBodyFrames;
internal Task Http2BeforeHandlerTask;
/// <summary>
/// Priority used only in HTTP/2
/// </summary>
internal long? Priority;
/// <summary>
/// Keeps the body data after the session is finished.
/// </summary>
......@@ -189,11 +205,13 @@ namespace Titanium.Web.Proxy.Http
public bool IsBodyRead { get; internal set; }
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// Is the request/response no more modifiable 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; }
internal bool BodyAvailable => BodyInternal != null;
internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true);
/// <summary>
......
namespace Titanium.Web.Proxy.Http
{
public enum TunnelType
{
Unknown,
Https,
Websocket,
Http2,
}
}
......@@ -61,7 +61,9 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <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)
/// <param name="indexType">Index type.</param>
/// <param name="useStaticName">Use static name.</param>
public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false, HpackUtil.IndexType indexType = HpackUtil.IndexType.Incremental, bool useStaticName = true)
{
// If the header value is sensitive then it must never be indexed
if (sensitive)
......@@ -116,10 +118,9 @@ namespace Titanium.Web.Proxy.Http2.Hpack
}
else
{
int nameIndex = getNameIndex(name);
int nameIndex = useStaticName ? getNameIndex(name) : -1;
ensureCapacity(headerSize);
var indexType = HpackUtil.IndexType.Incremental;
encodeLiteral(output, name, value, indexType, nameIndex);
add(name, value);
}
......@@ -309,7 +310,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
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))
if (e.Hash == h && name.Equals(e.Name, StringComparison.OrdinalIgnoreCase) && Equals(value, e.Value))
{
return e;
}
......@@ -336,7 +337,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
int index = -1;
for (var e = headerFields[i]; e != null; e = e.Next)
{
if (e.Hash == h && HpackUtil.Equals(name, e.Name))
if (e.Hash == h && name.Equals(e.Name, StringComparison.OrdinalIgnoreCase))
{
index = e.Index;
break;
......@@ -513,7 +514,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <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)
public HeaderEntry(int hash, string name, string value, int index, HeaderEntry next) : base(name, value, true)
{
Index = index;
Hash = hash;
......
......@@ -59,102 +59,102 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/* 14 */
new HttpHeader(":status", "500"),
/* 15 */
new HttpHeader("accept-charset", string.Empty),
new HttpHeader("Accept-Charset", string.Empty),
/* 16 */
new HttpHeader("accept-encoding", "gzip, deflate"),
new HttpHeader("Accept-Encoding", "gzip, deflate"),
/* 17 */
new HttpHeader("accept-language", string.Empty),
new HttpHeader("Accept-Language", string.Empty),
/* 18 */
new HttpHeader("accept-ranges", string.Empty),
new HttpHeader("Accept-Ranges", string.Empty),
/* 19 */
new HttpHeader("accept", string.Empty),
new HttpHeader("Accept", string.Empty),
/* 20 */
new HttpHeader("access-control-allow-origin", string.Empty),
new HttpHeader("Access-Control-Allow-Origin", string.Empty),
/* 21 */
new HttpHeader("age", string.Empty),
new HttpHeader("Age", string.Empty),
/* 22 */
new HttpHeader("allow", string.Empty),
new HttpHeader("Allow", string.Empty),
/* 23 */
new HttpHeader("authorization", string.Empty),
new HttpHeader("Authorization", string.Empty),
/* 24 */
new HttpHeader("cache-control", string.Empty),
new HttpHeader("Cache-Control", string.Empty),
/* 25 */
new HttpHeader("content-disposition", string.Empty),
new HttpHeader("Content-Disposition", string.Empty),
/* 26 */
new HttpHeader("content-encoding", string.Empty),
new HttpHeader("Content-Encoding", string.Empty),
/* 27 */
new HttpHeader("content-language", string.Empty),
new HttpHeader("Content-Language", string.Empty),
/* 28 */
new HttpHeader("content-length", string.Empty),
new HttpHeader("Content-Length", string.Empty),
/* 29 */
new HttpHeader("content-location", string.Empty),
new HttpHeader("Content-Location", string.Empty),
/* 30 */
new HttpHeader("content-range", string.Empty),
new HttpHeader("Content-Range", string.Empty),
/* 31 */
new HttpHeader("content-type", string.Empty),
new HttpHeader("Content-Type", string.Empty),
/* 32 */
new HttpHeader("cookie", string.Empty),
new HttpHeader("Cookie", string.Empty),
/* 33 */
new HttpHeader("date", string.Empty),
new HttpHeader("Date", string.Empty),
/* 34 */
new HttpHeader("etag", string.Empty),
new HttpHeader("ETag", string.Empty),
/* 35 */
new HttpHeader("expect", string.Empty),
new HttpHeader("Expect", string.Empty),
/* 36 */
new HttpHeader("expires", string.Empty),
new HttpHeader("Expires", string.Empty),
/* 37 */
new HttpHeader("from", string.Empty),
new HttpHeader("From", string.Empty),
/* 38 */
new HttpHeader("host", string.Empty),
new HttpHeader("Host", string.Empty),
/* 39 */
new HttpHeader("if-match", string.Empty),
new HttpHeader("If-Match", string.Empty),
/* 40 */
new HttpHeader("if-modified-since", string.Empty),
new HttpHeader("If-Modified-Since", string.Empty),
/* 41 */
new HttpHeader("if-none-match", string.Empty),
new HttpHeader("If-None-Match", string.Empty),
/* 42 */
new HttpHeader("if-range", string.Empty),
new HttpHeader("If-Range", string.Empty),
/* 43 */
new HttpHeader("if-unmodified-since", string.Empty),
new HttpHeader("If-Unmodified-Since", string.Empty),
/* 44 */
new HttpHeader("last-modified", string.Empty),
new HttpHeader("Last-Modified", string.Empty),
/* 45 */
new HttpHeader("link", string.Empty),
new HttpHeader("Link", string.Empty),
/* 46 */
new HttpHeader("location", string.Empty),
new HttpHeader("Location", string.Empty),
/* 47 */
new HttpHeader("max-forwards", string.Empty),
new HttpHeader("Max-Forwards", string.Empty),
/* 48 */
new HttpHeader("proxy-authenticate", string.Empty),
new HttpHeader("Proxy-Authenticate", string.Empty),
/* 49 */
new HttpHeader("proxy-authorization", string.Empty),
new HttpHeader("Proxy-Authorization", string.Empty),
/* 50 */
new HttpHeader("range", string.Empty),
new HttpHeader("Range", string.Empty),
/* 51 */
new HttpHeader("referer", string.Empty),
new HttpHeader("Referer", string.Empty),
/* 52 */
new HttpHeader("refresh", string.Empty),
new HttpHeader("Refresh", string.Empty),
/* 53 */
new HttpHeader("retry-after", string.Empty),
new HttpHeader("Retry-After", string.Empty),
/* 54 */
new HttpHeader("server", string.Empty),
new HttpHeader("Server", string.Empty),
/* 55 */
new HttpHeader("set-cookie", string.Empty),
new HttpHeader("Set-Cookie", string.Empty),
/* 56 */
new HttpHeader("strict-transport-security", string.Empty),
new HttpHeader("Strict-Transport-Security", string.Empty),
/* 57 */
new HttpHeader("transfer-encoding", string.Empty),
new HttpHeader("Transfer-Encoding", string.Empty),
/* 58 */
new HttpHeader("user-agent", string.Empty),
new HttpHeader("User-Agent", string.Empty),
/* 59 */
new HttpHeader("vary", string.Empty),
new HttpHeader("Vary", string.Empty),
/* 60 */
new HttpHeader("via", string.Empty),
new HttpHeader("Via", string.Empty),
/* 61 */
new HttpHeader("www-authenticate", string.Empty)
new HttpHeader("WWW-Authenticate", string.Empty)
};
private static readonly Dictionary<string, int> staticIndexByName = CreateMap();
private static readonly Dictionary<string, int> staticIndexByName = createMap();
/// <summary>
/// The number of header fields in the static table.
......@@ -180,12 +180,12 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <param name="name">Name.</param>
public static int GetIndex(string name)
{
if (!staticIndexByName.ContainsKey(name))
if (!staticIndexByName.TryGetValue(name, out int index))
{
return -1;
}
return staticIndexByName[name];
return index;
}
/// <summary>
......@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
while (index <= Length)
{
var entry = Get(index);
if (!HpackUtil.Equals(name, entry.Name))
if (!name.Equals(entry.Name, StringComparison.OrdinalIgnoreCase))
{
break;
}
......@@ -227,7 +227,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// create a map of header name to index value to allow quick lookup
/// </summary>
/// <returns>The map.</returns>
private static Dictionary<string, int> CreateMap()
private static Dictionary<string, int> createMap()
{
int length = staticTable.Count;
var ret = new Dictionary<string, int>(length);
......@@ -237,11 +237,11 @@ namespace Titanium.Web.Proxy.Http2.Hpack
for (int index = length; index > 0; index--)
{
var entry = Get(index);
string name = entry.Name;
string name = entry.Name.ToLower();
ret[name] = index;
}
return ret;
}
}
}
\ No newline at end of file
}
using System;
namespace Titanium.Web.Proxy.Http2
{
[Flags]
internal enum Http2FrameFlag : byte
{
Ack = 0x01,
EndStream = 0x01,
EndHeaders = 0x04,
Padded = 0x08,
Priority = 0x20,
}
}
\ No newline at end of file
namespace Titanium.Web.Proxy.Http2
{
internal class Http2FrameHeader
{
public int Length;
public Http2FrameType Type;
public Http2FrameFlag Flags;
public int StreamId;
public byte[] Buffer;
public byte[] CopyToBuffer()
{
int length = Length;
var buf = /*new byte[9];*/Buffer;
buf[0] = (byte)((length >> 16) & 0xff);
buf[1] = (byte)((length >> 8) & 0xff);
buf[2] = (byte)(length & 0xff);
buf[3] = (byte)Type;
buf[4] = (byte)Flags;
int streamId = StreamId;
//buf[5] = (byte)((streamId >> 24) & 0xff);
//buf[6] = (byte)((streamId >> 16) & 0xff);
//buf[7] = (byte)((streamId >> 8) & 0xff);
//buf[8] = (byte)(streamId & 0xff);
return buf;
}
}
}
namespace Titanium.Web.Proxy.Http2
{
internal enum Http2FrameType : byte
{
Data = 0x00,
Headers = 0x01,
Priority = 0x02,
RstStream = 0x03,
Settings = 0x04,
PushPromise = 0x05,
Ping = 0x06,
GoAway = 0x07,
WindowUpdate = 0x08,
Continuation = 0x09,
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -31,7 +31,7 @@ namespace Titanium.Web.Proxy.Models
/// Intercept tunnel connect request.
/// Valid only for explicit endpoints.
/// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl" /> property to false if this HTTP connect request
/// should'nt be decrypted and instead be relayed.
/// shouldn't be decrypted and instead be relayed.
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest;
......@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Models
}
}
internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer,
internal async Task InvokeBeforeTunnelConnectResponse(ProxyServer proxyServer,
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
{
if (BeforeTunnelConnectResponse != null)
......
......@@ -70,7 +70,7 @@ namespace Titanium.Web.Proxy.Models
public int Port { get; set; }
/// <summary>
/// Get cache key for Tcp connection cahe.
/// Get cache key for Tcp connection cache.
/// </summary>
/// <returns></returns>
internal string GetCacheKey()
......
......@@ -35,17 +35,24 @@ namespace Titanium.Web.Proxy.Models
{
if (string.IsNullOrEmpty(name))
{
throw new Exception("Name cannot be null");
throw new Exception("Name cannot be null or empty");
}
Name = name.Trim();
Value = value.Trim();
}
protected HttpHeader(string name, string value, bool headerEntry)
{
// special header entry created in inherited class with empty name
Name = name.Trim();
Value = value.Trim();
}
/// <summary>
/// Header Name.
/// </summary>
public string Name { get; set; }
public string Name { get; }
/// <summary>
/// Header Value.
......
......@@ -143,8 +143,16 @@ namespace Titanium.Web.Proxy.Network.Certificate
#if NET45
// Set private key onto certificate instance
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
X509Certificate2 x509Certificate;
if (RunTime.IsRunningOnMono)
{
x509Certificate = withPrivateKey(certificate, rsaparams);
}
else
{
x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
}
#else
var x509Certificate = withPrivateKey(certificate, rsaparams);
#endif
......
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
......@@ -49,7 +49,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary>
/// A list of pending certificate creation tasks.
/// Usefull to prevent multiple threads working on same certificate generation
/// Useful to prevent multiple threads working on same certificate generation
/// when burst certificate generation requests happen for same certificate.
/// </summary>
private readonly ConcurrentDictionary<string, Task<X509Certificate2>> pendingCertificateCreationTasks
......@@ -149,7 +149,7 @@ namespace Titanium.Web.Proxy.Network
set
{
// For Mono (or Non-Windows) only Bouncy Castle is supported
if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
value = CertificateEngine.BouncyCastle;
}
......@@ -662,7 +662,7 @@ namespace Titanium.Web.Proxy.Network
/// <returns>True if success.</returns>
public bool TrustRootCertificateAsAdmin(bool machineTrusted = false)
{
if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
return false;
}
......@@ -805,7 +805,7 @@ namespace Titanium.Web.Proxy.Network
/// <returns>Should also remove from machine store?</returns>
public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false)
{
if (!RunTime.IsWindows || RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
return false;
}
......
#if DEBUG

using Titanium.Web.Proxy.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
#if DEBUG
using System;
using System.IO;
using System.Text;
using System.Threading;
using StreamExtended;
using StreamExtended.Network;
namespace Titanium.Web.Proxy.Network
{
......
......@@ -59,6 +59,12 @@ namespace Titanium.Web.Proxy.Network
private X509Certificate2 loadCertificate(string path, string password, X509KeyStorageFlags storageFlags)
{
byte[] exported;
if (!File.Exists(path))
{
return null;
}
try
{
exported = File.ReadAllBytes(path);
......
using StreamExtended.Network;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Network
{
......
......@@ -7,6 +7,8 @@ using System.Net.Security;
using System.Net.Sockets;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network.Tcp
{
......@@ -34,11 +36,42 @@ namespace Titanium.Web.Proxy.Network.Tcp
private readonly TcpClient tcpClient;
private int? processId;
public Stream GetStream()
{
return tcpClient.GetStream();
}
public int GetProcessId(ProxyEndPoint endPoint)
{
if (processId.HasValue)
{
return processId.Value;
}
if (RunTime.IsWindows)
{
var remoteEndPoint = (IPEndPoint)RemoteEndPoint;
// If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
var ipVersion = endPoint.IpV6Enabled ? IpVersion.Ipv6 : IpVersion.Ipv4;
processId = TcpHelper.GetProcessIdByLocalPort(ipVersion, remoteEndPoint.Port);
}
else
{
// can't access process Id of remote request from remote machine
processId = -1;
}
return processId.Value;
}
throw new PlatformNotSupportedException();
}
/// <summary>
/// Dispose.
/// </summary>
......
......@@ -8,12 +8,12 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Network.Tcp
{
......@@ -38,11 +38,11 @@ namespace Titanium.Web.Proxy.Network.Tcp
internal TcpConnectionFactory(ProxyServer server)
{
this.server = server;
this.Server = server;
Task.Run(async () => await clearOutdatedConnections());
}
internal ProxyServer server { get; set; }
internal ProxyServer Server { get; }
internal string GetConnectionCacheKey(string remoteHostName, int remotePort,
bool isHttps, List<SslApplicationProtocol> applicationProtocols,
......@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
//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.
//That can create cache miss for same server connection unnecessarily especially when prefetching with Connect.
//http version 2 is separated using applicationProtocols below.
var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" +
//when creating Tcp client isConnect won't matter
......@@ -232,7 +232,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
CancellationToken cancellationToken)
{
//deny connection to proxy end points to avoid infinite connection loop.
if (server.ProxyEndPoints.Any(x => x.Port == remotePort)
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}");
......@@ -240,7 +240,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
if (externalProxy != null)
{
if (server.ProxyEndPoints.Any(x => x.Port == externalProxy.Port)
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}");
......@@ -271,16 +271,14 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
tcpClient = new TcpClient(upStreamEndPoint)
{
NoDelay = proxyServer.NoDelay,
NoDelay = proxyServer.NoDelay,
ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000,
SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000,
SendBufferSize = proxyServer.BufferSize,
ReceiveBufferSize = proxyServer.BufferSize,
LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds)
};
//linux has a bug with socket reuse in .net core.
if (proxyServer.ReuseSocket && (RunTime.IsWindows || RunTime.IsRunningOnMono))
if (proxyServer.ReuseSocket && RunTime.IsWindows)
{
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
......@@ -418,7 +416,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
return;
}
if (close || connection.IsWinAuthenticated || !server.EnableConnectionPool)
if (close || connection.IsWinAuthenticated || !Server.EnableConnectionPool || connection.IsClosed)
{
disposalBag.Add(connection);
return;
......@@ -434,7 +432,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
if (cache.TryGetValue(connection.CacheKey, out var existingConnections))
{
while (existingConnections.Count >= server.MaxCachedConnections)
while (existingConnections.Count >= Server.MaxCachedConnections)
{
if (existingConnections.TryDequeue(out var staleConnection))
{
......@@ -491,16 +489,17 @@ namespace Titanium.Web.Proxy.Network.Tcp
{
if (queue.TryDequeue(out var connection))
{
var cutOff = DateTime.Now.AddSeconds(-1 * server.ConnectionTimeOutSeconds);
if (!server.EnableConnectionPool
var cutOff = DateTime.Now.AddSeconds(-1 * Server.ConnectionTimeOutSeconds);
if (!Server.EnableConnectionPool
|| connection.LastAccess < cutOff)
{
disposalBag.Add(connection);
continue;
}
queue.Enqueue(connection);
break;
else
{
queue.Enqueue(connection);
break;
}
}
}
}
......@@ -531,7 +530,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
}
catch (Exception e)
{
server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e));
Server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e));
}
finally
{
......
......@@ -5,10 +5,10 @@ using System.Net.Security;
#endif
using System.Net.Sockets;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy.Network.Tcp
{
......@@ -27,6 +27,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
private ProxyServer proxyServer { get; }
internal bool IsClosed => Stream.IsClosed;
internal ExternalProxy UpStreamProxy { get; set; }
internal string HostName { get; set; }
......
//
//
// Mono.Security.BitConverterLE.cs
// Like System.BitConverter but always little endian
//
......
......@@ -11,7 +11,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy")]
[assembly: AssemblyCopyright("Copyright Titanium 2015-2017")]
[assembly: AssemblyCopyright("Copyright Titanium 2015-2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("Titanium.Web.Proxy.UnitTests, PublicKey=" +
......
......@@ -7,8 +7,6 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
......@@ -16,6 +14,8 @@ 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.StreamExtended.BufferPool;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy
{
......@@ -57,6 +57,7 @@ namespace Titanium.Web.Proxy
/// </summary>
private WinHttpWebProxyFinder systemProxyResolver;
/// <inheritdoc />
/// <summary>
/// Initializes a new instance of ProxyServer class with provided parameters.
......@@ -102,7 +103,7 @@ namespace Titanium.Web.Proxy
ProxyEndPoints = new List<ProxyEndPoint>();
tcpConnectionFactory = new TcpConnectionFactory(this);
if (!RunTime.IsRunningOnMono && RunTime.IsWindows && !RunTime.IsUwpOnWindows)
if (RunTime.IsWindows && !RunTime.IsUwpOnWindows)
{
systemProxySettingsManager = new SystemProxyManager();
}
......@@ -143,9 +144,17 @@ namespace Titanium.Web.Proxy
/// Defaults to false.
/// </summary>
public bool EnableWinAuth { get; set; }
/// <summary>
/// Enable disable HTTP/2 support.
/// Warning: HTTP/2 support is very limited
/// - only enabled when both client and server supports it (no protocol changing in proxy)
/// - cannot modify the request/response (e.g header modifications in BeforeRequest/Response events are ignored)
/// </summary>
public bool EnableHttp2 { get; set; } = false;
/// <summary>
/// Should we check for certificare revocation during SSL authentication to servers
/// Should we check for certificate revocation during SSL authentication to servers
/// Note: If enabled can reduce performance. Defaults to false.
/// </summary>
public X509RevocationMode CheckCertificateRevocation { get; set; }
......@@ -168,7 +177,7 @@ namespace Titanium.Web.Proxy
/// When enabled, as soon as we receive a client connection we concurrently initiate
/// corresponding server connection process using CONNECT hostname or SNI hostname on a separate task so that after parsing client request
/// we will have the server connection immediately ready or in the process of getting ready.
/// If a server connection is available in cache then this prefetch task will immediatly return with the available connection from cache.
/// If a server connection is available in cache then this prefetch task will immediately return with the available connection from cache.
/// Defaults to true.
/// </summary>
public bool EnableTcpServerConnectionPrefetch { get; set; } = true;
......@@ -352,6 +361,11 @@ namespace Titanium.Web.Proxy
/// </summary>
public event AsyncEventHandler<TcpClient> OnServerConnectionCreate;
/// <summary>
/// Customize the minimum ThreadPool size (increase it on a server)
/// </summary>
public int ThreadPoolWorkerThread { get; set; } = Environment.ProcessorCount;
/// <summary>
/// Add a proxy end point.
/// </summary>
......@@ -374,7 +388,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Remove a proxy end point.
/// Will throw error if the end point does'nt exist.
/// Will throw error if the end point doesn't exist.
/// </summary>
/// <param name="endPoint">The existing endpoint to remove.</param>
public void RemoveEndPoint(ProxyEndPoint endPoint)
......@@ -417,9 +431,10 @@ namespace Titanium.Web.Proxy
/// <param name="protocolType">The proxy protocol type.</param>
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType)
{
if (RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
throw new Exception("Mono Runtime do not support system proxy settings.");
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually confugure you operating system to use this proxy's port and address.");
}
validateEndPointAsSystemProxy(endPoint);
......@@ -510,9 +525,10 @@ namespace Titanium.Web.Proxy
/// </summary>
public void DisableSystemProxy(ProxyProtocolType protocolType)
{
if (RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
throw new Exception("Mono Runtime do not support system proxy settings.");
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually confugure you operating system to use this proxy's port and address.");
}
systemProxySettingsManager.RemoveProxy(protocolType);
......@@ -523,9 +539,10 @@ namespace Titanium.Web.Proxy
/// </summary>
public void DisableAllSystemProxies()
{
if (RunTime.IsRunningOnMono)
if (!RunTime.IsWindows)
{
throw new Exception("Mono Runtime do not support system proxy settings.");
throw new NotSupportedException(@"Setting system proxy settings are only supported in Windows.
Please manually confugure you operating system to use this proxy's port and address.");
}
systemProxySettingsManager.DisableAllProxy();
......@@ -541,6 +558,8 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is already running.");
}
setThreadPoolMinThread(ThreadPoolWorkerThread);
if (ProxyEndPoints.OfType<ExplicitProxyEndPoint>().Any(x => x.GenericCertificate == null))
{
CertificateManager.EnsureRootCertificate();
......@@ -599,7 +618,7 @@ namespace Titanium.Web.Proxy
throw new Exception("Proxy is not running.");
}
if (!RunTime.IsRunningOnMono && RunTime.IsWindows && !RunTime.IsUwpOnWindows)
if (RunTime.IsWindows && !RunTime.IsUwpOnWindows)
{
bool setAsSystemProxy = ProxyEndPoints.OfType<ExplicitProxyEndPoint>()
.Any(x => x.IsSystemHttpProxy || x.IsSystemHttpsProxy);
......@@ -632,7 +651,7 @@ namespace Titanium.Web.Proxy
endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port);
//linux/macOS has a bug with socket reuse in .net core.
if (ReuseSocket && (RunTime.IsWindows || RunTime.IsRunningOnMono))
if (ReuseSocket && RunTime.IsWindows)
{
endPoint.Listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
......@@ -718,13 +737,32 @@ 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);
}
/// <summary>
/// Change the ThreadPool.WorkerThread minThread
/// </summary>
/// <param name="workerThreads">minimum Threads allocated in the ThreadPool</param>
private void setThreadPoolMinThread(int workerThreads)
{
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minCompletionPortThreads);
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out _);
minWorkerThreads = Math.Min(maxWorkerThreads, Math.Max(workerThreads, Environment.ProcessorCount));
ThreadPool.SetMinThreads(minWorkerThreads, minCompletionPortThreads);
}
/// <summary>
/// Handle the client.
/// </summary>
......@@ -735,8 +773,7 @@ namespace Titanium.Web.Proxy
{
tcpClient.ReceiveTimeout = ConnectionTimeOutSeconds * 1000;
tcpClient.SendTimeout = ConnectionTimeOutSeconds * 1000;
tcpClient.SendBufferSize = BufferSize;
tcpClient.ReceiveBufferSize = BufferSize;
tcpClient.LingerState = new LingerOption(true, TcpTimeWaitSeconds);
await InvokeConnectionCreateEvent(tcpClient, true);
......
......@@ -2,13 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
......@@ -18,6 +18,7 @@ using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.StreamExtended.Network;
namespace Titanium.Web.Proxy
{
......@@ -27,7 +28,7 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer
{
private bool isWindowsAuthenticationEnabledAndSupported =>
EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono;
EnableWinAuth && RunTime.IsWindows;
/// <summary>
/// This is the core request handler method for a particular connection from client.
......@@ -43,7 +44,7 @@ namespace Titanium.Web.Proxy
/// The https hostname as appeared in CONNECT request if this is a HTTPS request from
/// explicit endpoint.
/// </param>
/// <param name="connectRequest">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <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,
......@@ -60,7 +61,7 @@ namespace Titanium.Web.Proxy
{
var cancellationToken = cancellationTokenSource.Token;
// Loop through each subsequest request on this particular client connection
// Loop through each subsequent request on this particular client connection
// (assuming HTTP connection is kept alive by client)
while (true)
{
......@@ -188,8 +189,20 @@ namespace Titanium.Web.Proxy
//If prefetch task is available.
if (connection == null && prefetchTask != null)
{
connection = await prefetchTask;
try
{
connection = await prefetchTask;
}
catch (SocketException e)
{
if(e.SocketErrorCode != SocketError.HostNotFound)
{
throw;
}
}
prefetchTask = null;
}
// create a new connection if cache key changes.
......@@ -299,6 +312,8 @@ namespace Titanium.Web.Proxy
if (args.HttpClient.Request.UpgradeToWebSocket)
{
args.HttpClient.ConnectRequest.TunnelType = TunnelType.Websocket;
// if upgrading to websocket then relay the request without reading the contents
await handleWebSocketUpgrade(httpCmd, args, args.HttpClient.Request,
args.HttpClient.Response, args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamWriter,
......@@ -360,7 +375,7 @@ namespace Titanium.Web.Proxy
}
/// <summary>
/// Prepare the request headers so that we can avoid encodings not parsable by this proxy
/// Prepare the request headers so that we can avoid encodings not parseable by this proxy
/// </summary>
private void prepareRequestHeaders(HeaderCollection requestHeaders)
{
......
......@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer
{
/// <summary>
/// Called asynchronously when a request was successfull and we received the response.
/// Called asynchronously when a request was successful and we received the response.
/// </summary>
/// <param name="args">The session event arguments.</param>
/// <returns> The task.</returns>
......@@ -92,7 +92,7 @@ namespace Titanium.Web.Proxy
// clear current response
await args.ClearResponse(cancellationToken);
var httpCmd = Request.CreateRequestLine(args.HttpClient.Request.Method,
args.HttpClient.Request.OriginalUrl, args.HttpClient.Request.HttpVersion);
args.HttpClient.Request.RequestUriString, args.HttpClient.Request.HttpVersion);
await handleHttpSessionRequest(httpCmd, args, null, args.ClientConnection.NegotiatedApplicationProtocol,
cancellationToken, args.CancellationTokenSource);
return;
......@@ -125,7 +125,6 @@ namespace Titanium.Web.Proxy
}
args.TimeLine["Response Sent"] = DateTime.Now;
}
/// <summary>
......
using System;
namespace Titanium.Web.Proxy.StreamExtended.BufferPool
{
/// <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);
}
}
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.
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