Unverified Commit 603223a7 authored by honfika's avatar honfika Committed by GitHub

Merge pull request #361 from justcoding121/develop

beta|develop
parents 80dd44e5 0a3c9bb5
......@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="StreamExtended, Version=1.0.132.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.132-beta\lib\net45\StreamExtended.dll</HintPath>
<Reference Include="StreamExtended, Version=1.0.135.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.135-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="StreamExtended" version="1.0.132-beta" targetFramework="net45" />
<package id="StreamExtended" version="1.0.135-beta" targetFramework="net45" />
</packages>
\ No newline at end of file
......@@ -2,7 +2,7 @@
A light weight 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/rvlxv8xgj0m7lkr4?svg=true)</a>
<a href="https://ci.appveyor.com/project/justcoding121/titanium-web-proxy">![Build Status](https://ci.appveyor.com/api/projects/status/rvlxv8xgj0m7lkr4?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)
Kindly report only issues/bugs here . For programming help or questions use [StackOverflow](http://stackoverflow.com/questions/tagged/titanium-web-proxy) with the tag Titanium-Web-Proxy.
......
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Titanium_002EWeb_002EProxy_002EExamples_002EWpf_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_EMBEDDED_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
......@@ -21,6 +24,11 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=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_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>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
......@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Helpers
private readonly char[] charBuffer;
private static readonly byte[] newLine = ProxyConstants.NewLine;
private static readonly Encoder encoder = Encoding.ASCII.GetEncoder();
internal HttpWriter(Stream stream, int bufferSize) : base(stream)
......@@ -33,18 +33,30 @@ namespace Titanium.Web.Proxy.Helpers
return WriteAsync(newLine);
}
public async Task WriteAsync(string value)
public Task WriteAsync(string value)
{
int charCount = value.Length;
value.CopyTo(0, charBuffer, 0, charCount);
return WriteAsyncInternal(value, false);
}
if (charCount < BufferSize)
private Task WriteAsyncInternal(string value, bool addNewLine)
{
int newLineChars = addNewLine ? newLine.Length : 0;
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);
await WriteAsync(buffer, 0, idx);
if (newLineChars > 0)
{
Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
idx += newLineChars;
}
return WriteAsync(buffer, 0, idx);
}
finally
{
......@@ -53,16 +65,24 @@ namespace Titanium.Web.Proxy.Helpers
}
else
{
var buffer = new byte[charCount + 1];
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);
await WriteAsync(buffer, 0, idx);
if (newLineChars > 0)
{
Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
idx += newLineChars;
}
return WriteAsync(buffer, 0, idx);
}
}
public async Task WriteLineAsync(string value)
public Task WriteLineAsync(string value)
{
await WriteAsync(value);
await WriteLineAsync();
return WriteAsyncInternal(value, true);
}
/// <summary>
......
......@@ -4,6 +4,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Network.Tcp;
......@@ -109,15 +110,115 @@ 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
/// Asynchronous Programming Model, which does not throw exceptions when the socket is closed
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive)
internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc)
{
var tcs = new TaskCompletionSource<bool>();
var cts = new CancellationTokenSource();
cts.Token.Register(() => tcs.TrySetResult(true));
//Now async relay all server=>client & client=>server data
byte[] clientBuffer = BufferPool.GetBuffer(bufferSize);
byte[] serverBuffer = BufferPool.GetBuffer(bufferSize);
try
{
BeginRead(clientStream, serverStream, clientBuffer, cts, onDataSend, exceptionFunc);
BeginRead(serverStream, clientStream, serverBuffer, cts, onDataReceive, exceptionFunc);
await tcs.Task;
}
finally
{
BufferPool.ReturnBuffer(clientBuffer);
BufferPool.ReturnBuffer(serverBuffer);
}
}
private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, CancellationTokenSource cts, Action<byte[], int, int> onCopy, Action<Exception> exceptionFunc)
{
if (cts.IsCancellationRequested)
{
return;
}
bool readFlag = false;
var readCallback = (AsyncCallback)(ar =>
{
if (cts.IsCancellationRequested || readFlag)
{
return;
}
readFlag = true;
try
{
int read = inputStream.EndRead(ar);
if (read <= 0)
{
cts.Cancel();
return;
}
onCopy?.Invoke(buffer, 0, read);
var writeCallback = (AsyncCallback)(ar2 =>
{
if (cts.IsCancellationRequested)
{
return;
}
try
{
outputStream.EndWrite(ar2);
BeginRead(inputStream, outputStream, buffer, cts, onCopy, exceptionFunc);
}
catch (IOException ex)
{
cts.Cancel();
exceptionFunc(ex);
}
});
outputStream.BeginWrite(buffer, 0, read, writeCallback, null);
}
catch (IOException ex)
{
cts.Cancel();
exceptionFunc(ex);
}
});
var readResult = inputStream.BeginRead(buffer, 0, buffer.Length, readCallback, null);
if (readResult.CompletedSynchronously)
{
readCallback(readResult);
}
}
/// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers as prefix
/// Usefull for websocket requests
/// Task-based Asynchronous Pattern
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc)
{
var cts = new CancellationTokenSource();
......
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Org.BouncyCastle.Asn1;
......@@ -132,9 +133,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
var rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1,
rsa.Exponent2, rsa.Coefficient);
#if NET45
// Set private key onto certificate instance
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
#else
var x509Certificate = WithPrivateKey(certificate, rsaparams);
x509Certificate.FriendlyName = subjectName;
#endif
if (!doNotSetFriendlyName)
{
......@@ -151,6 +157,22 @@ namespace Titanium.Web.Proxy.Network.Certificate
return x509Certificate;
}
private static X509Certificate2 WithPrivateKey(Org.BouncyCastle.X509.X509Certificate certificate, AsymmetricKeyParameter privateKey)
{
const string password = "password";
var store = new Pkcs12Store();
var entry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(certificate.SubjectDN.ToString(), entry);
store.SetKeyEntry(certificate.SubjectDN.ToString(), new AsymmetricKeyEntry(privateKey), new[] { entry });
using (var ms = new MemoryStream())
{
store.Save(ms, password.ToCharArray(), new SecureRandom(new CryptoApiRandomGenerator()));
return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
}
}
/// <summary>
/// Makes the certificate internal.
/// </summary>
......
using System;
using StreamExtended.Network;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
......@@ -7,7 +8,6 @@ using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
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;
......@@ -438,7 +438,7 @@ namespace Titanium.Web.Proxy
if (isHttp)
{
endPoint.IsSystemHttpsProxy = true;
endPoint.IsSystemHttpProxy = true;
}
if (isHttps)
......
......@@ -194,9 +194,10 @@ namespace Titanium.Web.Proxy
((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
}
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
await TcpHelper.SendRawApm(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); });
(buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
ExceptionFunc);
}
return;
......@@ -441,9 +442,10 @@ namespace Titanium.Web.Proxy
await BeforeResponse.InvokeAsync(this, args, ExceptionFunc);
}
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
await TcpHelper.SendRawApm(clientStream, connection.Stream, BufferSize,
(buffer, offset, count) => { args.OnDataSent(buffer, offset, count); },
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); });
(buffer, offset, count) => { args.OnDataReceived(buffer, offset, count); },
ExceptionFunc);
args.Dispose();
break;
......
......@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.3" />
<PackageReference Include="StreamExtended" Version="1.0.132-beta" />
<PackageReference Include="StreamExtended" Version="1.0.135-beta" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......
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