Commit 27fc293a authored by titanium007's avatar titanium007

Merge remote-tracking branch 'refs/remotes/origin/master' into breaking-change

# Conflicts:
#	README.md
#	Titanium.Web.Proxy.Test/App.config
#	Titanium.Web.Proxy.Test/Properties/AssemblyInfo.cs
#	Titanium.Web.Proxy.sln
#	Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
#	Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs
#	Titanium.Web.Proxy/Helpers/Tcp.cs
#	Titanium.Web.Proxy/Properties/AssemblyInfo.cs
#	Titanium.Web.Proxy/ProxyServer.cs
#	Titanium.Web.Proxy/RequestHandler.cs
#	Titanium.Web.Proxy/ResponseHandler.cs
#	Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
#	Titanium.Web.Proxy/packages.config
parent 4c3121ed
param (
[string]$Action="default",
[hashtable]$properties=@{},
[switch]$Help
)
$Here = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
Import-Module "$Here\Common"
Install-Chocolatey
Install-Psake
$psakeDirectory = (Resolve-Path $env:ChocolateyInstall\lib\Psake*)
Import-Module (Join-Path $psakeDirectory "tools\Psake.psm1")
if($Help)
{
try
{
Write-Host "Available build tasks:"
psake -nologo -docs | Out-Host -paging
}
catch {}
return
}
Invoke-Psake -buildFile "$Here\Default.ps1" -parameters $properties -tasklist $Action
\ No newline at end of file
###
### Common Profile functions for all users
###
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$SolutionRoot = Split-Path -Parent $ScriptPath
$ToolsPath = Join-Path -Path $SolutionRoot -ChildPath "lib"
Export-ModuleMember -Variable @('ScriptPath', 'SolutionRoot', 'ToolsPath')
function Install-Chocolatey()
{
if(-not $env:ChocolateyInstall -or -not (Test-Path "$env:ChocolateyInstall"))
{
Write-Output "Chocolatey Not Found, Installing..."
iex ((new-object net.webclient).DownloadString('http://chocolatey.org/install.ps1'))
}
}
function Install-Psake()
{
if(!(Test-Path $env:ChocolateyInstall\lib\Psake*))
{
choco install psake -y
}
}
Export-ModuleMember -Function *-*
\ No newline at end of file
$PSake.use_exit_on_error = $true
$Here = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$SolutionRoot = (Split-Path -parent $Here)
$ProjectName = "Titanium.Web.Proxy"
$SolutionFile = "$SolutionRoot\$ProjectName.sln"
## This comes from the build server iteration
if(!$BuildNumber) { $BuildNumber = $env:APPVEYOR_BUILD_NUMBER }
if(!$BuildNumber) { $BuildNumber = "1"}
## This comes from the Hg commit hash used to build
if(!$CommitHash) { $CommitHash = $env:APPVEYOR_REPO_COMMIT }
if(!$CommitHash) { $CommitHash = "local-build" }
## The build configuration, i.e. Debug/Release
if(!$Configuration) { $Configuration = $env:Configuration }
if(!$Configuration) { $Configuration = "Release" }
if(!$Version) { $Version = $env:APPVEYOR_BUILD_VERSION }
if(!$Version) { $Version = "1.0.$BuildNumber" }
Import-Module "$Here\Common" -DisableNameChecking
$NuGet = Join-Path $SolutionRoot ".nuget\nuget.exe"
$MSBuild ="${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\msbuild.exe"
FormatTaskName (("-"*25) + "[{0}]" + ("-"*25))
Task default -depends Clean, Build, Package
Task Build -depends Restore-Packages {
exec { . $MSBuild $SolutionFile /t:Build /v:normal /p:Configuration=$Configuration }
exec { . $MSBuild $SolutionFile /t:Build /v:normal /p:Configuration=$Configuration-Net45 }
}
Task Package -depends Build {
exec { . $NuGet pack "$SolutionRoot\Titanium.Web.Proxy\Titanium.Web.Proxy.nuspec" -Properties Configuration=$Configuration -OutputDirectory "$SolutionRoot" -Version "$Version" }
}
Task Clean -depends Install-BuildTools {
Remove-Item -Path "$SolutionRoot\packages\*" -Exclude repositories.config -Recurse -Force
Get-ChildItem .\ -include bin,obj -Recurse | foreach ($_) { Remove-Item $_.fullname -Force -Recurse }
exec { . $MSBuild $SolutionFile /t:Clean /v:quiet }
}
Task Restore-Packages {
exec { . $NuGet restore $SolutionFile }
}
Task Install-MSBuild {
if(!(Test-Path "${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\msbuild.exe"))
{
cinst microsoft-build-tools -y
}
}
Task Install-BuildTools -depends Install-MSBuild
......@@ -2,7 +2,7 @@ Titanium
========
A light weight http(s) proxy server written in C#
[![titanium MyGet Build Status](https://www.myget.org/BuildSource/Badge/titanium?identifier=36bd545d-87aa-4c0c-ae98-6de9a078b016)](https://www.myget.org/)
![Build Status](https://ci.appveyor.com/api/projects/status/rvlxv8xgj0m7lkr4?svg=true)
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.
......@@ -11,10 +11,9 @@ Kindly report only issues/bugs here . For programming help or questions use [Sta
Features
========
* Supports Http(s) and all features of HTTP 1.1
* Supports Http(s) and most features of HTTP 1.1
* Supports relaying of WebSockets
* Supports script injection
* Async using HttpWebRequest class for better performance
Usage
=====
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Http.Tests
{
class Program
{
static void Main(string[] args)
{
var t = Task.Factory.StartNew(Test);
t.Wait();
Console.Read();
}
public static async void Test()
{
var s = new HttpClient
{
Method = "GET",
Uri = new Uri("https://google.com"),
Version = "HTTP/1.1"
};
s.RequestHeaders.Add(new HttpHeader("Host", s.Uri.Host));
await s.SendRequest();
await s.ReceiveResponse();
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Titanium.Web.Http.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Http.Tests")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ef2b516c-1cc2-4688-af05-0758b40bb9df")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{95550A47-B2D2-43C4-8E79-17BDF09B797F}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Titanium.Web.Http.Tests</RootNamespace>
<AssemblyName>Titanium.Web.Http.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Titanium.Web.Http\Titanium.Web.Http.csproj">
<Project>{51f8273a-39e4-4c9f-9972-bc78f8b3b32e}</Project>
<Name>Titanium.Web.Http</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl" version="1.1.8" targetFramework="net40" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Instrumentation;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Http
{
public class HttpClient
{
const string Space = " ";
public string Method { get; set; }
public Uri Uri { get; set; }
public string Version { get; set; }
public List<HttpHeader> RequestHeaders { get; set; }
public bool IsSecure
{
get { return this.Uri.Scheme == Uri.UriSchemeHttps; }
}
public TcpClient Client { get; set; }
public Stream Stream { get; set; }
public HttpClient()
{
RequestHeaders = new List<HttpHeader>();
ResponseHeaders = new List<HttpHeader>();
}
public async Task<Stream> GetStream()
{
if (Stream == null)
{
Client = new TcpClient(Uri.Host, Uri.Port);
Stream = Client.GetStream();
if (IsSecure)
{
SslStream sslStream = null;
try
{
sslStream = new SslStream(Stream);
await sslStream.AuthenticateAsClientAsync(Uri.Host);
Stream = sslStream;
}
catch
{
if (sslStream != null)
sslStream.Dispose();
throw;
}
}
}
return Stream;
}
public async Task SendRequest()
{
await GetStream();
var requestLines = new StringBuilder();
requestLines.Append(string.Join(Space, Method, Uri.AbsolutePath, Version));
requestLines.AppendLine();
foreach (var header in RequestHeaders)
{
requestLines.Append(header.Name + ':' + header.Value);
requestLines.AppendLine();
requestLines.AppendLine();
}
var request = requestLines.ToString();
var requestBytes = Encoding.ASCII.GetBytes(request);
await Stream.WriteAsync(requestBytes, 0, requestBytes.Length);
await Stream.FlushAsync();
}
public string Status { get; set; }
public List<HttpHeader> ResponseHeaders { get; set; }
public async Task ReceiveResponse()
{
var responseLines = await HttpStreamReader.ReadAllLines(Stream);
var responseStatus = responseLines[0].Split(' ');
Status = responseStatus[1] + Space + responseStatus[2];
for (int i = 1; i < responseLines.Count; i++)
{
var header = responseLines[i].Split(':');
ResponseHeaders.Add(new HttpHeader(header[0], header[1]));
}
}
public void Abort()
{
throw new NotImplementedException();
}
public int ContentLength { get; set; }
public bool SendChunked { get; set; }
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Titanium.Web.Http")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Http")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e951d607-dfa6-43b2-ad9a-8dcdea29a0f1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Titanium.Web.Http</RootNamespace>
<AssemblyName>Titanium.Web.Http</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CustomBinaryReader.cs" />
<Compile Include="HttpHeader.cs" />
<Compile Include="HttpClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl" version="1.1.8" targetFramework="net40" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40" />
</packages>
\ No newline at end of file
......@@ -8,11 +8,11 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.10.0" newVersion="2.6.10.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.10.0" newVersion="2.6.10.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
using System.Reflection;
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
......@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Demo")]
[assembly: AssemblyCopyright("Copyright ©2013 Telerik")]
[assembly: AssemblyCopyright("Copyright ©2013 Telerik")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......@@ -33,7 +33,7 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
// [assembly: AssemblyVersion("1.0.1")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
[assembly: AssemblyVersion("1.0.1")]
[assembly: AssemblyFileVersion("1.0.1")]
......@@ -10,9 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Titanium.Web.Proxy.Test</RootNamespace>
<AssemblyName>Titanium.Web.Proxy.Test</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
......@@ -22,6 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
......@@ -30,10 +29,31 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Net45|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug-Net45\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-Net45|AnyCPU'">
<OutputPath>bin\Release-Net45\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
......
......@@ -16,66 +16,36 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B8
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HttpClient", "HttpClient", "{867333C8-3C44-41F4-913C-63802970CF82}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Http", "Titanium.Web.Http\Titanium.Web.Http.csproj", "{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Http.Tests", "Titanium.Web.Http.Tests\Titanium.Web.Http.Tests.csproj", "{95550A47-B2D2-43C4-8E79-17BDF09B797F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Debug-Net45|Any CPU = Debug-Net45|Any CPU
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
Release-Net45|Any CPU = Release-Net45|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|x64.ActiveCfg = Debug|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|x86.ActiveCfg = Debug|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug-Net45|Any CPU.ActiveCfg = Debug-Net45|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug-Net45|Any CPU.Build.0 = Debug-Net45|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.Build.0 = Release|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|x64.ActiveCfg = Release|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|x86.ActiveCfg = Release|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release-Net45|Any CPU.ActiveCfg = Release-Net45|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release-Net45|Any CPU.Build.0 = Release-Net45|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|x64.ActiveCfg = Debug|x64
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|x64.Build.0 = Debug|x64
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|x86.ActiveCfg = Debug|x86
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug|x86.Build.0 = Debug|x86
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug-Net45|Any CPU.ActiveCfg = Debug-Net45|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Debug-Net45|Any CPU.Build.0 = Debug-Net45|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|Any CPU.Build.0 = Release|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x64.ActiveCfg = Release|x64
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x64.Build.0 = Release|x64
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x86.ActiveCfg = Release|x86
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x86.Build.0 = Release|x86
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Debug|x64.ActiveCfg = Debug|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Debug|x86.ActiveCfg = Debug|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Release|Any CPU.Build.0 = Release|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Release|x64.ActiveCfg = Release|Any CPU
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E}.Release|x86.ActiveCfg = Release|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Debug|x64.ActiveCfg = Debug|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Debug|x86.ActiveCfg = Debug|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Release|Any CPU.Build.0 = Release|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Release|x64.ActiveCfg = Release|Any CPU
{95550A47-B2D2-43C4-8E79-17BDF09B797F}.Release|x86.ActiveCfg = Release|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release-Net45|Any CPU.ActiveCfg = Release-Net45|Any CPU
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release-Net45|Any CPU.Build.0 = Release-Net45|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F3B7E553-1904-4E80-BDC7-212342B5C952} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B}
{51F8273A-39E4-4C9F-9972-BC78F8B3B32E} = {867333C8-3C44-41F4-913C-63802970CF82}
{95550A47-B2D2-43C4-8E79-17BDF09B797F} = {867333C8-3C44-41F4-913C-63802970CF82}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
......
......@@ -6,10 +6,10 @@ using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Titanium.Web.Http;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.EventArguments
{
......@@ -24,6 +24,7 @@ namespace Titanium.Web.Proxy.EventArguments
internal TcpClient Client { get; set; }
internal Stream ClientStream { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
......@@ -43,7 +44,7 @@ namespace Titanium.Web.Proxy.EventArguments
internal bool RequestBodyRead { get; set; }
public List<HttpHeader> RequestHeaders { get; internal set; }
internal bool RequestLocked { get; set; }
internal HttpClient ProxyRequest { get; set; }
internal HttpWebClient ProxySession { get; set; }
internal Encoding ResponseEncoding { get; set; }
internal Stream ResponseStream { get; set; }
......@@ -52,7 +53,6 @@ namespace Titanium.Web.Proxy.EventArguments
internal bool ResponseBodyRead { get; set; }
public List<HttpHeader> ResponseHeaders { get; internal set; }
internal bool ResponseLocked { get; set; }
// internal HttpWebResponse ProxyRequest { get; set; }
public int RequestContentLength
{
......@@ -69,13 +69,13 @@ namespace Titanium.Web.Proxy.EventArguments
public string RequestMethod
{
get { return ProxyRequest.Method; }
get { return ProxySession.Method; }
}
public HttpStatusCode ResponseStatusCode
public string ResponseStatusCode
{
get { return ProxyRequest.StatusCode; }
get { return ProxySession.ResponseStatusCode; }
}
public string ResponseContentType
......@@ -90,19 +90,19 @@ namespace Titanium.Web.Proxy.EventArguments
public void Dispose()
{
if (ProxyRequest != null)
ProxyRequest.Abort();
//if (ProxyRequest != null)
// ProxyRequest.Abort();
if (ResponseStream != null)
ResponseStream.Dispose();
if (ProxyRequest != null)
ProxyRequest.Close();
//if (ServerResponse != null)
// ServerResponse.Close();
}
private void ReadRequestBody()
{
if ((ProxyRequest.Method.ToUpper() != "POST" && ProxyRequest.Method.ToUpper() != "PUT"))
if ((ProxySession.Method.ToUpper() != "POST" && ProxySession.Method.ToUpper() != "PUT"))
{
throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
......@@ -168,7 +168,7 @@ namespace Titanium.Web.Proxy.EventArguments
RequestBody = CompressionHelper.DecompressDeflate(requestBodyStream);
break;
case "zlib":
RequestBody = CompressionHelper.DecompressGzip(requestBodyStream);
RequestBody = CompressionHelper.DecompressZlib(requestBodyStream);
break;
default:
RequestBody = requestBodyStream.ToArray();
......@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (ResponseBody == null)
{
switch (ProxyRequest.ContentEncoding)
switch ( ProxySession.ResponseContentEncoding)
{
case "gzip":
ResponseBody = CompressionHelper.DecompressGzip(ResponseStream);
......@@ -265,7 +265,7 @@ namespace Titanium.Web.Proxy.EventArguments
public void SetRequestBodyString(string body)
{
if (RequestLocked) throw new Exception("Youcannot call this function after request is made to server.");
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (!RequestBodyRead)
{
......
using System.Net;
using System.Text;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebRequestExtensions
{
public static Encoding GetEncoding(this HttpWebRequest request)
public static Encoding GetEncoding(this HttpWebClient request)
{
try
{
if (request.ContentType == null) return Encoding.GetEncoding("ISO-8859-1");
if (request.RequestContentType == null) return Encoding.GetEncoding("ISO-8859-1");
var contentTypes = request.ContentType.Split(';');
var contentTypes = request.RequestContentType.Split(';');
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
......
using System.Net;
using System.Text;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebResponseExtensions
{
public static Encoding GetEncoding(this HttpWebResponse response)
public static Encoding GetResponseEncoding(this HttpWebClient response)
{
if (string.IsNullOrEmpty(response.CharacterSet)) return Encoding.GetEncoding("ISO-8859-1");
return Encoding.GetEncoding(response.CharacterSet.Replace(@"""",string.Empty));
if (string.IsNullOrEmpty(response.ResponseCharacterSet)) return Encoding.GetEncoding("ISO-8859-1");
return Encoding.GetEncoding(response.ResponseCharacterSet.Replace(@"""",string.Empty));
}
}
}
\ No newline at end of file
......@@ -2,28 +2,39 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Http
namespace Titanium.Web.Proxy.Helpers
{
public class HttpStreamReader
public class CustomBinaryReader : BinaryReader
{
internal CustomBinaryReader(Stream stream, Encoding encoding)
: base(stream, encoding)
{
}
public async static Task<string> ReadLine(Stream stream)
internal string ReadLine()
{
var buf = new byte[2];
var readBuffer = new StringBuilder();
try
{
while ((await stream.ReadAsync(buf, 0, 2)) > 0)
var lastChar = default(char);
var buffer = new char[1];
while (Read(buffer, 0, 1) > 0)
{
if (lastChar == '\r' && buffer[0] == '\n')
{
var charRead = System.Text.Encoding.ASCII.GetString(buf);
if (charRead == Environment.NewLine)
return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
}
if (buffer[0] == '\0')
{
return readBuffer.ToString();
}
readBuffer.Append(charRead);
readBuffer.Append(buffer);
lastChar = buffer[0];
}
return readBuffer.ToString();
}
catch (IOException)
......@@ -32,12 +43,11 @@ namespace Titanium.Web.Http
}
}
public async static Task<List<string>> ReadAllLines(Stream stream)
internal List<string> ReadAllLines()
{
string tmpLine;
var requestLines = new List<string>();
while (!string.IsNullOrEmpty(tmpLine = await ReadLine(stream)))
while (!string.IsNullOrEmpty(tmpLine = ReadLine()))
{
requestLines.Add(tmpLine);
}
......
......@@ -6,9 +6,8 @@ using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Http;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Helpers
{
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Http
{
//public class HttpStreamReader
//{
// public static async Task<string> ReadLine(Stream stream)
// {
// var readBuffer = new StringBuilder();
// try
// {
// var lastChar = default(char);
// var buffer = new byte[1];
// while ((await stream.ReadAsync(buffer, 0, 1)) > 0)
// {
// if (lastChar == '\r' && buffer[0] == '\n')
// {
// return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
// }
// if (buffer[0] == '\0')
// {
// return readBuffer.ToString();
// }
// readBuffer.Append(Encoding.ASCII.GetString(buffer));
// lastChar = Encoding.ASCII.GetChars(buffer)[0];
// }
// return readBuffer.ToString();
// }
// catch (IOException)
// {
// return readBuffer.ToString();
// }
// }
// public static async Task<List<string>> ReadAllLines(Stream stream)
// {
// string tmpLine;
// var requestLines = new List<string>();
// while (!string.IsNullOrEmpty(tmpLine = await ReadLine(stream)))
// {
// requestLines.Add(tmpLine);
// }
// return requestLines;
// }
//}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http
{
public class HttpWebClient
{
private const string Space = " ";
public string Method { get; set; }
public Uri RequestUri { get; set; }
public string Version { get; set; }
public List<HttpHeader> RequestHeaders { get; set; }
public bool IsSecure
{
get
{
return this.RequestUri.Scheme == Uri.UriSchemeHttps;
}
}
public TcpClient Client { get; set; }
public string RequestStatus { get; set; }
public List<HttpHeader> ResponseHeaders { get; set; }
public int RequestContentLength { get; set; }
public bool RequestSendChunked { get; set; }
public HttpWebClient()
{
this.RequestHeaders = new List<HttpHeader>();
this.ResponseHeaders = new List<HttpHeader>();
}
public CustomBinaryReader ServerStreamReader { get; set; }
public async Task SendRequest()
{
Stream stream = Client.GetStream();
StringBuilder requestLines = new StringBuilder();
requestLines.AppendLine(string.Join(" ", new string[3]
{
this.Method,
this.RequestUri.AbsolutePath,
this.Version
}));
foreach (HttpHeader httpHeader in this.RequestHeaders)
{
requestLines.AppendLine(httpHeader.Name + ':' + httpHeader.Value);
}
requestLines.AppendLine();
requestLines.AppendLine();
string request = requestLines.ToString();
byte[] requestBytes = Encoding.ASCII.GetBytes(request);
await AsyncExtensions.WriteAsync((Stream)stream, requestBytes, 0, requestBytes.Length);
await AsyncExtensions.FlushAsync((Stream)stream);
}
public void ReceiveResponse()
{
Stream stream = Client.GetStream();
ServerStreamReader = new CustomBinaryReader(stream, Encoding.ASCII);
var httpResult = ServerStreamReader.ReadLine().Split(' ');
var httpVersion = httpResult[0];
Version version;
if (httpVersion == "HTTP/1.1")
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
this.ResponseProtocolVersion = version;
this.ResponseStatusCode = httpResult[1];
string status = httpResult[2];
for (int i = 3; i < httpResult.Length; i++)
{
status = status + Space + httpResult[i];
}
this.ResponseStatusDescription = status;
List<string> responseLines = ServerStreamReader.ReadAllLines();
for (int index = 0; index < responseLines.Count; ++index)
{
string[] strArray = responseLines[index].Split(':');
this.ResponseHeaders.Add(new HttpHeader(strArray[0], strArray[1]));
}
}
public string RequestContentType { get; set; }
public bool RequestKeepAlive { get; set; }
public string RequestHost { get; set; }
public string ResponseCharacterSet { get; set; }
public string ResponseContentEncoding { get; set; }
public System.Version ResponseProtocolVersion { get; set; }
public string ResponseStatusCode { get; set; }
public string ResponseStatusDescription { get; set; }
public bool ResponseKeepAlive { get; set; }
public string ResponseContentType { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.IO;
using System.Net.Security;
namespace Titanium.Web.Proxy.Http
{
internal class TcpConnectionManager
{
static ConcurrentDictionary<string, ConcurrentStack<TcpClient>> ConnectionCache = new ConcurrentDictionary<string, ConcurrentStack<TcpClient>>();
public static async Task<TcpClient> GetClient(string Hostname, int port, bool IsSecure)
{
var key = string.Concat(Hostname, ":", port, ":", IsSecure);
ConcurrentStack<TcpClient> connections;
if (!ConnectionCache.TryGetValue(key, out connections))
{
return await CreateClient(Hostname, port, IsSecure);
}
TcpClient client;
if (!connections.TryPop(out client))
{
return await CreateClient(Hostname, port, IsSecure);
}
return client;
}
private static async Task<TcpClient> CreateClient(string Hostname, int port, bool IsSecure)
{
var client = new TcpClient(Hostname, port);
var stream = (Stream)client.GetStream();
if (IsSecure)
{
var sslStream = (SslStream)null;
try
{
sslStream = new SslStream(stream);
await AsyncPlatformExtensions.AuthenticateAsClientAsync(sslStream, Hostname);
stream = (Stream)sslStream;
}
catch
{
if (sslStream != null)
sslStream.Dispose();
throw;
}
}
return client;
}
public static void AddClient(string Hostname, int port, bool IsSecure, TcpClient Client)
{
var key = string.Concat(Hostname, ":", port, ":", IsSecure);
ConcurrentStack<TcpClient> connections;
if (!ConnectionCache.TryGetValue(key, out connections))
{
connections = new ConcurrentStack<TcpClient>();
connections.Push(Client);
ConnectionCache.TryAdd(key, connections);
}
connections.Push(Client);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Titanium.Web.Http
namespace Titanium.Web.Proxy.Models
{
public class HttpHeader
{
public HttpHeader(string name, string value)
......
using System.Reflection;
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
......@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy.Properties")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
......@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
[assembly: AssemblyVersion("1.0.1")]
[assembly: AssemblyFileVersion("1.0.1")]
......@@ -61,7 +61,7 @@ namespace Titanium.Web.Proxy
{
ServicePointManager.Expect100Continue = false;
WebRequest.DefaultWebProxy = null;
ServicePointManager.DefaultConnectionLimit = 10;
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000; //3 minutes
ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000;
......@@ -73,9 +73,11 @@ namespace Titanium.Web.Proxy
return false;
};
#if NET40
//Fix a bug in .NET 4.0
NetFrameworkHelper.UrlPeriodFix();
//useUnsafeHeaderParsing
#endif
NetFrameworkHelper.ToggleAllowUnsafeHeaderParsing(true);
}
......@@ -98,7 +100,10 @@ namespace Titanium.Web.Proxy
{
SystemProxyHelper.EnableProxyHttp(
Equals(ListeningIpAddress, IPAddress.Any) ? "127.0.0.1" : ListeningIpAddress.ToString(), ListeningPort);
#if !DEBUG
FireFoxHelper.AddFirefox();
#endif
if (EnableSsl)
......@@ -126,7 +131,7 @@ namespace Titanium.Web.Proxy
_listener.BeginAcceptTcpClient(OnAcceptConnection, _listener);
var client = _listener.EndAcceptTcpClient(asyn);
var Task = HandleClient(client);
Task.Factory.StartNew(() => HandleClient(client));
}
catch
{
......@@ -140,7 +145,9 @@ namespace Titanium.Web.Proxy
if (SetAsSystemProxy)
{
SystemProxyHelper.DisableAllProxy();
#if !DEBUG
FireFoxHelper.RemoveFirefox();
#endif
}
_listener.Stop();
......
......@@ -10,30 +10,32 @@ using System.Security.Authentication;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Titanium.Web.Http;
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;
namespace Titanium.Web.Proxy
{
partial class ProxyServer
{
private static async Task HandleClient(TcpClient client)
private static void HandleClient(TcpClient client)
{
Stream clientStream = client.GetStream();
var clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
var clientStreamWriter = new StreamWriter(clientStream);
Uri httpRemoteUri;
try
{
//read the first line HTTP command
var httpCmd = await HttpStreamReader.ReadLine(clientStream);
var httpCmd = clientStreamReader.ReadLine();
if (string.IsNullOrEmpty(httpCmd))
{
throw new EndOfStreamException();
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return;
}
//break up the line into three components (method, remote URL & Http Version)
......@@ -54,7 +56,7 @@ namespace Titanium.Web.Proxy
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port == 443)
{
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
await HttpStreamReader.ReadAllLines(clientStream);
clientStreamReader.ReadAllLines();
WriteConnectResponse(clientStreamWriter, httpVersion);
......@@ -69,7 +71,7 @@ namespace Titanium.Web.Proxy
sslStream.AuthenticateAsServer(certificate, false,
SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
clientStreamWriter = new StreamWriter(sslStream);
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
......@@ -80,46 +82,49 @@ namespace Titanium.Web.Proxy
if (sslStream != null)
sslStream.Dispose();
throw;
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return;
}
httpCmd = await HttpStreamReader.ReadLine(clientStream);
httpCmd = clientStreamReader.ReadLine();
}
else if (httpVerb.ToUpper() == "CONNECT")
{
await HttpStreamReader.ReadAllLines(clientStream);
clientStreamReader.ReadAllLines();
WriteConnectResponse(clientStreamWriter, httpVersion);
TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
TcpHelper.SendRaw(clientStreamReader.BaseStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false);
Dispose(client, clientStream, null, clientStreamWriter, null);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return;
}
//Now create the request
HandleHttpSessionRequest(client, httpCmd, clientStream, null, clientStreamWriter,
HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null);
}
catch
{
Dispose(client, clientStream, null, clientStreamWriter, null);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
}
}
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
string clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
private static async void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
{
while (true)
{
if (string.IsNullOrEmpty(httpCmd))
{
Dispose(client, clientStream, null, clientStreamWriter, null);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
return;
}
var args = new SessionEventArgs(BUFFER_SIZE);
args.Client = client;
try
{
//break up the line into three components (method, remote URL & Http Version)
......@@ -149,7 +154,7 @@ namespace Titanium.Web.Proxy
string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await HttpStreamReader.ReadLine(clientStream)))
while (!string.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
var header = tmpLine.Split(ColonSpaceSplit, 2, StringSplitOptions.None);
args.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
......@@ -163,82 +168,90 @@ namespace Titanium.Web.Proxy
//if request was upgrade to web-socket protocol then relay the request without proxying
if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
{
TcpHelper.SendRaw(clientStream, httpCmd, args.RequestHeaders,
TcpHelper.SendRaw(clientStreamReader.BaseStream, httpCmd, args.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
Dispose(client, clientStream, null, clientStreamWriter, args);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
}
//construct the web request that we are going to issue on behalf of the client.
args.ProxyRequest = new HttpClient();
args.ProxySession = new Http.HttpWebClient();
args.ProxySession.RequestUri = httpRemoteUri;
//args.ProxyRequest.Proxy = null;
//args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = httpMethod;
//args.ProxyRequest.ProtocolVersion = version;
args.ProxySession.Method = httpMethod;
args.ProxySession.Version = httpVersion;
// args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
//args.ClientStreamReader = clientStreamReader;
args.ClientStreamReader = clientStreamReader;
args.ClientStreamWriter = clientStreamWriter;
// args.ProxyRequest.AllowAutoRedirect = false;
//args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
//args.RequestHostname = args.ProxyRequest.RequestUri.Host;
//args.RequestUrl = args.ProxyRequest.RequestUri.OriginalString;
// args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
args.RequestHostname = args.ProxySession.RequestUri.Host;
args.RequestUrl = args.ProxySession.RequestUri.OriginalString;
args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
args.RequestHttpVersion = version;
// args.RequestIsAlive = args.ProxyRequest.KeepAlive;
//args.ProxyRequest.ConnectionGroupName = args.RequestHostname;
//args.RequestIsAlive = args.ProxyRequest.KeepAlive;
//args.ProxyRequest.AllowWriteStreamBuffering = true;
args.Client = await TcpConnectionManager.GetClient(args.ProxySession.RequestUri.Host, args.ProxySession.RequestUri.Port, args.IsHttps);
args.ProxySession.Client = args.Client;
//If requested interception
if (BeforeRequest != null)
{
//args.RequestEncoding = args.ProxyRequest.GetEncoding();
//BeforeRequest(null, args);
args.RequestEncoding = args.ProxySession.GetEncoding();
BeforeRequest(null, args);
}
args.RequestLocked = true;
if (args.CancelRequest)
{
Dispose(client, clientStream, null, clientStreamWriter, args);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
SetRequestHeaders(args.RequestHeaders, args.ProxyRequest);
SetRequestHeaders(args.RequestHeaders, args.ProxySession);
await args.ProxySession.SendRequest();
//If request was modified by user
if (args.RequestBodyRead)
{
args.ProxyRequest.ContentLength = args.RequestBody.Length;
var newStream = await args.ProxyRequest.GetStream();
args.ProxySession.RequestContentLength = args.RequestBody.Length;
var newStream = args.ProxySession.ServerStreamReader.BaseStream;
newStream.Write(args.RequestBody, 0, args.RequestBody.Length);
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
}
else
{
//If its a post/put request, then read the client html body and send it to server
if (httpMethod.ToUpper() == "POST" || httpMethod.ToUpper() == "PUT")
{
await SendClientRequestBody(args);
SendClientRequestBody(args);
}
//Http request body sent, now wait asynchronously for response
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
}
//Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
//If client is pipeling the request, this will be immediately hit before response for previous request was made
httpCmd = await HttpStreamReader.ReadLine(args.ClientStream);
//Http request body sent, now wait for next request
HandleHttpSessionRequest(args.Client, httpCmd, args.ClientStream, null,
args.ClientStreamWriter, secureTunnelHostName);
await HandleHttpSessionResponse(args);
//if connection is closing exit
if (args.ResponseHeaders.Any(x => x.Name.ToLower() == "connection" && x.Value.ToLower() == "close"))
{
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
// read the next request
httpCmd = clientStreamReader.ReadLine();
}
catch
{
Dispose(client, clientStream, null, clientStreamWriter, args);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
}
}
......@@ -246,60 +259,61 @@ namespace Titanium.Web.Proxy
{
clientStreamWriter.WriteLine(httpVersion + " 200 Connection established");
clientStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
clientStreamWriter.WriteLine("connection:close");
//clientStreamWriter.WriteLine("connection:close");
clientStreamWriter.WriteLine();
clientStreamWriter.Flush();
}
private static void SetRequestHeaders(List<HttpHeader> requestHeaders, HttpClient webRequest)
private static void SetRequestHeaders(List<HttpHeader> requestHeaders, HttpWebClient webRequest)
{
for (var i = 0; i < requestHeaders.Count; i++)
{
//switch (requestHeaders[i].Name.ToLower())
//{
// case "accept":
switch (requestHeaders[i].Name.ToLower())
{
case "accept":
// webRequest.Accept = requestHeaders[i].Value;
// break;
// case "accept-encoding":
// webRequest.Headers.Add("Accept-Encoding", "gzip,deflate,zlib");
// break;
// case "cookie":
// webRequest.Headers["Cookie"] = requestHeaders[i].Value;
// break;
// case "connection":
// if (requestHeaders[i].Value.ToLower() == "keep-alive")
// webRequest.KeepAlive = true;
// break;
// case "content-length":
// int contentLen;
// int.TryParse(requestHeaders[i].Value, out contentLen);
// if (contentLen != 0)
// webRequest.ContentLength = contentLen;
// break;
// case "content-type":
// webRequest.ContentType = requestHeaders[i].Value;
// break;
// case "expect":
// if (requestHeaders[i].Value.ToLower() == "100-continue")
break;
case "accept-encoding":
requestHeaders[i].Value = "gzip,deflate,zlib";
break;
case "cookie":
//webRequest.Headers["Cookie"] = requestHeaders[i].Value;
break;
case "connection":
if (requestHeaders[i].Value.ToLower() == "keep-alive")
webRequest.RequestKeepAlive = true;
break;
case "content-length":
int contentLen;
int.TryParse(requestHeaders[i].Value, out contentLen);
if (contentLen != 0)
webRequest.RequestContentLength = contentLen;
break;
case "content-type":
webRequest.RequestContentType = requestHeaders[i].Value;
break;
case "expect":
//if (requestHeaders[i].Value.ToLower() == "100-continue")
// webRequest.ServicePoint.Expect100Continue = true;
// else
// webRequest.Expect = requestHeaders[i].Value;
// break;
// case "host":
// webRequest.Host = requestHeaders[i].Value;
// break;
// case "if-modified-since":
break;
case "host":
webRequest.RequestHost = requestHeaders[i].Value;
break;
case "if-modified-since":
// var sb = requestHeaders[i].Value.Trim().Split(SemiSplit);
// DateTime d;
// if (DateTime.TryParse(sb[0], out d))
// webRequest.IfModifiedSince = d;
// break;
// case "proxy-connection":
// if (requestHeaders[i].Value.ToLower() == "keep-alive")
// webRequest.KeepAlive = true;
// break;
// case "range":
break;
case "proxy-connection":
if (requestHeaders[i].Value.ToLower() == "keep-alive")
webRequest.RequestKeepAlive = true;
else if (requestHeaders[i].Value.ToLower() == "close")
webRequest.RequestKeepAlive = false;
break;
case "range":
// var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
// if (startEnd.Length > 1)
// {
......@@ -309,44 +323,45 @@ namespace Titanium.Web.Proxy
// }
// else
// webRequest.AddRange(int.Parse(startEnd[0]));
// break;
// case "referer":
break;
case "referer":
// webRequest.Referer = requestHeaders[i].Value;
// break;
// case "user-agent":
break;
case "user-agent":
// webRequest.UserAgent = requestHeaders[i].Value;
// break;
break;
// //revisit this, transfer-encoding is not a request header according to spec
// //But how to identify if client is sending chunked body for PUT/POST?
// case "transfer-encoding":
// if (requestHeaders[i].Value.ToLower().Contains("chunked"))
// webRequest.SendChunked = true;
// else
// webRequest.SendChunked = false;
// break;
// case "upgrade":
//revisit this, transfer-encoding is not a request header according to spec
//But how to identify if client is sending chunked body for PUT/POST?
case "transfer-encoding":
if (requestHeaders[i].Value.ToLower().Contains("chunked"))
webRequest.RequestSendChunked = true;
else
webRequest.RequestSendChunked = false;
break;
case "upgrade":
// if (requestHeaders[i].Value.ToLower() == "http/1.1")
// webRequest.Headers.Add("Upgrade", requestHeaders[i].Value);
// break;
break;
// default:
default:
// webRequest.Headers.Add(requestHeaders[i].Name, requestHeaders[i].Value);
// break;
//}
requestHeaders.Add(new HttpHeader(requestHeaders[i].Name, requestHeaders[i].Value));
break;
}
}
webRequest.RequestHeaders = requestHeaders;
}
//This is called when the request is PUT/POST to read the body
private static async Task SendClientRequestBody(SessionEventArgs args)
private static void SendClientRequestBody(SessionEventArgs args)
{
// End the operation
var postStream = args.ProxyRequest.Stream;
var postStream = args.ProxySession.ServerStreamReader;
if (args.ProxyRequest.ContentLength > 0)
if (args.ProxySession.RequestContentLength > 0)
{
//args.ProxyRequest.AllowWriteStreamBuffering = true;
try
......@@ -354,26 +369,25 @@ namespace Titanium.Web.Proxy
var totalbytesRead = 0;
int bytesToRead;
if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
if (args.ProxySession.RequestContentLength < BUFFER_SIZE)
{
bytesToRead = (int)args.ProxyRequest.ContentLength;
bytesToRead = (int)args.ProxySession.RequestContentLength;
}
else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
while (totalbytesRead < (int)args.ProxySession.RequestContentLength)
{
var buffer = new byte[bytesToRead];
args.ClientStream.Read(buffer, 0, bytesToRead);
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead);
totalbytesRead += buffer.Length;
var remainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
var remainingBytes = (int)args.ProxySession.RequestContentLength - totalbytesRead;
if (remainingBytes < bytesToRead)
{
bytesToRead = remainingBytes;
}
postStream.Write(buffer, 0, buffer.Length);
postStream.BaseStream.Write(buffer, 0, buffer.Length);
}
postStream.Close();
......@@ -386,33 +400,32 @@ namespace Titanium.Web.Proxy
}
}
//Need to revist, find any potential bugs
else if (args.ProxyRequest.SendChunked)
else if (args.ProxySession.RequestSendChunked)
{
// args.ProxyRequest.AllowWriteStreamBuffering = true;
//args.ProxyRequest.AllowWriteStreamBuffering = true;
try
{
while (true)
{
var chuchkHead = await HttpStreamReader.ReadLine(args.ClientStream);
var chuchkHead = args.ClientStreamReader.ReadLine();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0)
{
var buffer = new byte[chunkSize];
args.ClientStream.Read(buffer,0,chunkSize);
postStream.Write(buffer, 0, buffer.Length);
var buffer = args.ClientStreamReader.ReadBytes(chunkSize);
postStream.BaseStream.Write(buffer, 0, buffer.Length);
//chunk trail
await HttpStreamReader.ReadLine(args.ClientStream);
args.ClientStreamReader.ReadLine();
}
else
{
await HttpStreamReader.ReadLine(args.ClientStream);
args.ClientStreamReader.ReadLine();
break;
}
}
postStream.Close();
}
catch
......
......@@ -6,11 +6,11 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Titanium.Web.Http;
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;
namespace Titanium.Web.Proxy
{
......@@ -20,20 +20,18 @@ namespace Titanium.Web.Proxy
private static async Task HandleHttpSessionResponse(SessionEventArgs args)
{
await args.ProxyRequest.ReceiveResponse();
args.ProxySession.ReceiveResponse();
try
{
if (args.ProxyRequest != null)
{
args.ResponseHeaders = ReadResponseHeaders(args.ProxyRequest);
args.ResponseStream = args.ProxyRequest.GetResponseStream();
args.ResponseHeaders = ReadResponseHeaders(args.ProxySession);
args.ResponseStream = args.ProxySession.ServerStreamReader.BaseStream;
if (BeforeResponse != null)
{
args.ResponseEncoding = args.ProxyRequest.GetEncoding();
args.ResponseEncoding = args.ProxySession.GetResponseEncoding();
BeforeResponse(null, args);
}
......@@ -41,8 +39,8 @@ namespace Titanium.Web.Proxy
if (args.ResponseBodyRead)
{
var isChunked = args.ProxyRequest.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked");
var contentEncoding = args.ProxyRequest.ContentEncoding;
var isChunked = args.ProxySession.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked"));
var contentEncoding = args.ProxySession.ResponseContentEncoding;
switch (contentEncoding.ToLower())
{
......@@ -57,28 +55,28 @@ namespace Titanium.Web.Proxy
break;
}
WriteResponseStatus(args.ProxyRequest.ProtocolVersion, args.ProxyRequest.StatusCode,
args.ProxyRequest.StatusDescription, args.ClientStreamWriter);
WriteResponseStatus(args.ProxySession.ResponseProtocolVersion, args.ProxySession.ResponseStatusCode,
args.ProxySession.ResponseStatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders, args.ResponseBody.Length,
isChunked);
WriteResponseBody(args.ClientStream, args.ResponseBody, isChunked);
}
else
{
var isChunked = args.ProxyRequest.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked");
// var isChunked = args.ProxySession.ResponseHeaders.Any(x => x.Name.ToLower() == "transfer-encoding" && x.Value.ToLower().Contains("chunked"));
WriteResponseStatus(args.ProxyRequest.ProtocolVersion, args.ProxyRequest.StatusCode,
args.ProxyRequest.StatusDescription, args.ClientStreamWriter);
WriteResponseStatus(args.ProxySession.ResponseProtocolVersion, args.ProxySession.ResponseStatusCode,
args.ProxySession.ResponseStatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders);
WriteResponseBody(args.ResponseStream, args.ClientStream, isChunked);
WriteResponseBody(args.ResponseStream, args.ClientStream, false);
}
args.ClientStream.Flush();
}
}
catch
{
Dispose(args.Client, args.ClientStream, null, args.ClientStreamWriter, args);
Dispose(args.Client, args.ClientStream, args.ClientStreamReader, args.ClientStreamWriter, args);
}
finally
{
......@@ -86,39 +84,43 @@ namespace Titanium.Web.Proxy
}
}
private static List<HttpHeader> ReadResponseHeaders(HttpWebResponse response)
private static List<HttpHeader> ReadResponseHeaders(HttpWebClient response)
{
var returnHeaders = new List<HttpHeader>();
string cookieHeaderName = null;
string cookieHeaderValue = null;
foreach (string headerKey in response.Headers.Keys)
for (var i = 0; i < response.ResponseHeaders.Count; i++)
{
switch (response.ResponseHeaders[i].Name.ToLower())
{
if (headerKey.ToLower() == "set-cookie")
case "content-encoding":
response.ResponseContentEncoding = response.ResponseHeaders[i].Value;
break;
case "content-type":
if (response.ResponseHeaders[i].Value.Contains(";"))
{
cookieHeaderName = headerKey;
cookieHeaderValue = response.Headers[headerKey];
response.ResponseContentType = response.ResponseHeaders[i].Value.Split(';')[0].Trim();
response.ResponseCharacterSet = response.ResponseHeaders[i].Value.Split(';')[1].Replace("charset=", string.Empty).Trim();
}
else
returnHeaders.Add(new HttpHeader(headerKey, response.Headers[headerKey]));
}
response.ResponseContentType = response.ResponseHeaders[i].Value.Trim();
if (!string.IsNullOrWhiteSpace(cookieHeaderValue))
{
response.Headers.Remove(cookieHeaderName);
var cookies = CookieSplitRegEx.Split(cookieHeaderValue);
foreach (var cookie in cookies)
returnHeaders.Add(new HttpHeader("Set-Cookie", cookie));
break;
case "connection":
break;
default:
break;
}
}
// response.ResponseHeaders.RemoveAll(x => x.Name.ToLower() == "connection");
return returnHeaders;
return response.ResponseHeaders;
}
private static void WriteResponseStatus(Version version, HttpStatusCode code, string description,
private static void WriteResponseStatus(Version version, string code, string description,
StreamWriter responseWriter)
{
var s = string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, (int)code, description);
var s = string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description);
responseWriter.WriteLine(s);
}
......@@ -126,6 +128,8 @@ namespace Titanium.Web.Proxy
{
if (headers != null)
{
//FixProxyHeaders(headers);
foreach (var header in headers)
{
responseWriter.WriteLine(header.ToString());
......@@ -135,10 +139,24 @@ namespace Titanium.Web.Proxy
responseWriter.WriteLine();
responseWriter.Flush();
}
private static void FixProxyHeaders(List<HttpHeader> headers)
{
//If proxy-connection close was returned inform to close the connection
if (headers.Any(x => x.Name.ToLower() == "proxy-connection" && x.Value.ToLower() == "close"))
if (headers.Any(x => x.Name.ToLower() == "connection") == false)
{
headers.Add(new HttpHeader("connection", "close"));
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
else
headers.Find(x => x.Name.ToLower() == "connection").Value = "close";
}
private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length,
bool isChunked)
{
FixProxyHeaders(headers);
if (!isChunked)
{
if (headers.Any(x => x.Name.ToLower() == "content-length") == false)
......
......@@ -10,68 +10,51 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Titanium.Web.Proxy</RootNamespace>
<AssemblyName>Titanium.Web.Proxy</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<DefineConstants>DEBUG;NET40</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<OutputPath>bin\Release\</OutputPath>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<DefineConstants>NET40</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
<CodeAnalysisFailOnMissingRules>true</CodeAnalysisFailOnMissingRules>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Net45|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug-Net45\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
<CodeAnalysisFailOnMissingRules>true</CodeAnalysisFailOnMissingRules>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-Net45|AnyCPU'">
<OutputPath>bin\Release-Net45\</OutputPath>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="Ionic.Zip">
<HintPath>..\packages\DotNetZip.1.9.3\lib\net20\Ionic.Zip.dll</HintPath>
<Reference Include="Ionic.Zip, Version=1.9.7.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\DotNetZip.1.9.7\lib\net20\Ionic.Zip.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
......@@ -80,14 +63,14 @@
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.IO">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.IO.dll</HintPath>
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Runtime.dll</HintPath>
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.8\lib\net40\System.Threading.Tasks.dll</HintPath>
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
......@@ -102,9 +85,13 @@
<Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Http\TcpConnectionManager.cs" />
<Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" />
<Compile Include="Helpers\NetFramework.cs" />
<Compile Include="Helpers\Compression.cs" />
<Compile Include="ProxyServer.cs" />
......@@ -112,12 +99,7 @@
<Compile Include="Helpers\Tcp.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Titanium.Web.Http\Titanium.Web.Http.csproj">
<Project>{51f8273a-39e4-4c9f-9972-bc78f8b3b32e}</Project>
<Name>Titanium.Web.Http</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
......
......@@ -13,11 +13,14 @@
<releaseNotes></releaseNotes>
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags>
<dependencies>
<dependency id="DotNetZip" version="1.9.7" />
</dependencies>
</metadata>
<files>
<file src="Titanium.Web.Proxy\bin\$configuration$\Titanium.Web.Proxy.dll" target="lib\net40\" />
<file src="Titanium.Web.Proxy\bin\$configuration$\Ionic.Zip.dll" target="lib\net40\" />
<file src="Titanium.Web.Proxy\bin\$configuration$\makecert.exe" target="content" />
<file src="Titanium.Web.Proxy\bin\$configuration$\Titanium_Proxy_Test_Root.cer" target="content" />
<file src="bin\$configuration$\Titanium.Web.Proxy.dll" target="lib\net40" />
<file src="bin\$configuration$-Net45\Titanium.Web.Proxy.dll" target="lib\net45" />
<file src="bin\$configuration$\makecert.exe" target="content" />
<file src="bin\$configuration$\Titanium_Proxy_Test_Root.cer" target="content" />
</files>
</package>
\ No newline at end of file
......@@ -4,11 +4,11 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.10.0" newVersion="2.6.10.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
<bindingRedirect oldVersion="0.0.0.0-2.6.10.0" newVersion="2.6.10.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DotNetZip" version="1.9.3" targetFramework="net40-Client" />
<package id="Microsoft.Bcl" version="1.1.8" targetFramework="net40-Client" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40-Client" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40-Client" />
<package id="DotNetZip" version="1.9.7" targetFramework="net40" />
<package id="DotNetZip" version="1.9.7" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net40" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net40" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40" />
</packages>
\ No newline at end of file
# AppVeyor CI build file
# Notes:
# - Minimal appveyor.yml file is an empty file. All sections are optional.
# - Indent each level of configuration with 2 spaces. Do not use tabs!
# - All section names are case-sensitive.
# - Section names should be unique on each level.
# version format
version: 1.1.{build}
shallow_clone: true
#---------------------------------#
# build configuration #
#---------------------------------#
# build platform, i.e. x86, x64, Any CPU. This setting is optional.
platform: Any CPU
# build Configuration, i.e. Debug, Release, etc.
configuration: Release
# to run your custom scripts instead of automatic MSBuild
build_script:
- cmd: .\build.bat Package
assembly_info:
patch: true
file: AssemblyInfo.*
assembly_version: "{version}"
assembly_file_version: "{version}"
assembly_informational_version: "{version}"
# to disable automatic tests
test: off
# skip building commits that add tags (such as release tag)
skip_tags: true
#---------------------------------#
# artifacts configuration #
#---------------------------------#
nuget:
account_feed: true
project_feed: true
disable_publish_on_pr: true # disable publishing of .nupkg artifacts to account/project feeds for pull request builds
artifacts:
- path: '**\Titanium.Web.Proxy.*.nupkg'
deploy:
- provider: GitHub
auth_token:
secure: ItVm+50ASpDXx1w+FCe2NTpZxqCbjRWfugLjk/bqBIi00DvPnSGOV1rIQ5hnwBW3
on:
branch: master
- provider: NuGet
api_key:
secure: ZbRmjOcp+TDllRV1wxqLZjdRV7hld388rXlWVJuGGiQleomP9Ku+Nsy3a75E7/9k
on:
branch: master
\ No newline at end of file
@echo Off
set config=%1
if "%config%" == "" (
set config=Release
)
@echo off
set version=1.0.0
if not "%PackageVersion%" == "" (
set version=%PackageVersion%
)
if '%1'=='/?' goto help
if '%1'=='-help' goto help
if '%1'=='-h' goto help
set nuget=
if "%nuget%" == "" (
set nuget=.nuget\nuget.exe
)
powershell -NoProfile -ExecutionPolicy bypass -Command "%~dp0.build\bootstrap.ps1 %*; if ($psake.build_success -eq $false) { exit 1 } else { exit 0 }"
exit /B %errorlevel%
%WINDIR%\Microsoft.NET\Framework\v4.0.30319\msbuild Titanium.Web.Proxy.sln /p:Configuration="%config%" /m /v:M /fl /flp:LogFile=msbuild.log;Verbosity=diag /nr:false
mkdir Build
mkdir Build\lib
mkdir Build\lib\net40
%nuget% pack "Titanium.Web.Proxy.nuspec" -NoPackageAnalysis -verbosity detailed -o Build -Version %version% -p Configuration="%config%"
\ No newline at end of file
:help
powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0.build\bootstrap.ps1' -help"
\ No newline at end of file
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