Commit 4c3121ed authored by titanium007's avatar titanium007

Replace HttpWebRequest with Custom Request Class

parent 606fe644
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<solution> <solution>
<add key="disableSourceControlIntegration" value="true" /> <add key="disableSourceControlIntegration" value="true" />
......
Titanium Titanium
======== ========
A light weight http(s) proxy server written in C# 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/)
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.
![alt tag](https://raw.githubusercontent.com/titanium007/Titanium/master/Titanium.Web.Proxy.Test/Capture.PNG) ![alt tag](https://raw.githubusercontent.com/titanium007/Titanium/master/Titanium.Web.Proxy.Test/Capture.PNG)
Features
========
* Supports Http(s) and all features of HTTP 1.1
* Supports relaying of WebSockets
* Supports script injection
* Async using HttpWebRequest class for better performance
Usage
=====
Refer the HTTP Proxy Server library in your project, look up Test project to learn usage.
Install by nuget:
Install-Package Titanium.Web.Proxy
After installing nuget package mark following files to be copied to app directory
* makecert.exe
* Titanium_Proxy_Test_Root.cer
Setup HTTP proxy:
```csharp
// listen to client request & server response events
ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse;
ProxyServer.EnableSSL = true;
ProxyServer.SetAsSystemProxy = true;
ProxyServer.Start();
//wait here (You can use something else as a wait function, I am using this as a demo)
Console.Read();
//Unsubscribe & Quit
ProxyServer.BeforeRequest -= OnRequest;
ProxyServer.BeforeResponse -= OnResponse;
ProxyServer.Stop();
```
Sample request and response event handlers
```csharp
//Test On Request, intercept requests
public void OnRequest(object sender, SessionEventArgs e)
{
Console.WriteLine(e.RequestURL);
//read request headers
var requestHeaders = e.RequestHeaders;
if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT") && e.RequestContentLength > 0)
{
//Get/Set request body bytes
byte[] bodyBytes = e.GetRequestBody();
e.SetRequestBody(bodyBytes);
//Get/Set request body as string
string bodyString = e.GetRequestBodyAsString();
e.SetRequestBodyString(bodyString);
}
//To cancel a request with a custom HTML content
//Filter URL
if (e.RequestURL.Contains("google.com"))
{
e.Ok("<!DOCTYPE html><html><body><h1>Website Blocked</h1><p>Blocked by titanium web proxy.</p></body></html>");
}
}
public void OnResponse(object sender, SessionEventArgs e)
{
//read response headers
var responseHeaders = e.ResponseHeaders;
if (e.ResponseStatusCode == HttpStatusCode.OK)
{
if (e.ResponseContentType.Trim().ToLower().Contains("text/html"))
{
//Get/Set response body bytes
byte[] responseBodyBytes = e.GetResponseBody();
e.SetResponseBody(responseBodyBytes);
//Get response body as string
string responseBody = e.GetResponseBodyAsString();
//Modify e.ServerResponse
Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1);
This project is still in progress. This will be updated once the project is stable. //Set modifed response Html Body
e.SetResponseBodyString(modified);
}
}
}
```
Future updates
============
* Support mutual authentication
* Support HTTP 2.0
* Support modification of web socket requests
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.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Http
{
public class HttpStreamReader
{
public async static Task<string> ReadLine(Stream stream)
{
var buf = new byte[2];
var readBuffer = new StringBuilder();
try
{
while ((await stream.ReadAsync(buf, 0, 2)) > 0)
{
var charRead = System.Text.Encoding.ASCII.GetString(buf);
if (charRead == Environment.NewLine)
{
return readBuffer.ToString();
}
readBuffer.Append(charRead);
}
return readBuffer.ToString();
}
catch (IOException)
{
return readBuffer.ToString();
}
}
public async static 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;
}
}
}
\ 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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Titanium.Web.Http
{
public class HttpHeader
{
public HttpHeader(string name, string value)
{
if (string.IsNullOrEmpty(name)) throw new Exception("Name cannot be null");
Name = name.Trim();
Value = value.Trim();
}
public string Name { get; set; }
public string Value { get; set; }
public override string ToString()
{
return string.Format("{0}: {1}", Name, Value);
}
}
}
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
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<configSections> <startup>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </startup>
</configSections> <runtime>
<connectionStrings> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<add name="SqlCELogConnectionString" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=Log.sdf" /> <dependentAssembly>
<add name="SqlCEEventsConnectionString" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=Events.sdf" /> <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<add name="SqlCEFilesConnectionString" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=Files.sdf" /> <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
<add name="SqlServerLogConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=ASXLog;Integrated Security=True;Enlist=False;" providerName="System.Data.SqlClient" /> </dependentAssembly>
<add name="SqlServerEventsConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=ASXEvents;Integrated Security=True;Enlist=False;" providerName="System.Data.SqlClient" /> <dependentAssembly>
<add name="SqlServerFilesConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=ASXFiles;Integrated Security=True;Enlist=False;" providerName="System.Data.SqlClient" /> <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<add name="SqlServerSettingsConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=ASXSettings;Integrated Security=True;Enlist=False;" providerName="System.Data.SqlClient" /> <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
</connectionStrings> </dependentAssembly>
<entityFramework> </assemblyBinding>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework"> </runtime>
<parameters>
<parameter value="System.Data.SqlServerCe.4.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="System.Data.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" />
</providers>
</entityFramework>
<unity configSource="unity.debug.xml" /> </configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" /></startup></configuration> \ No newline at end of file
Titanium.Web.Proxy.Test/Capture.PNG

23.8 KB | W: | H:

Titanium.Web.Proxy.Test/Capture.PNG

51.5 KB | W: | H:

Titanium.Web.Proxy.Test/Capture.PNG
Titanium.Web.Proxy.Test/Capture.PNG
Titanium.Web.Proxy.Test/Capture.PNG
Titanium.Web.Proxy.Test/Capture.PNG
  • 2-up
  • Swipe
  • Onion skin
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Test namespace Titanium.Web.Proxy.Test
{ {
public class Program public class Program
{ {
static ProxyTestController controller = new ProxyTestController(); private static readonly ProxyTestController Controller = new ProxyTestController();
public static void Main(string[] args) public static void Main(string[] args)
{ {
//On Console exit make sure we also exit the proxy //On Console exit make sure we also exit the proxy
handler = new ConsoleEventDelegate(ConsoleEventCallback); NativeMethods.Handler = ConsoleEventCallback;
SetConsoleCtrlHandler(handler, true); NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true);
Console.Write("Do you want to monitor HTTPS? (Y/N):"); Console.Write("Do you want to monitor HTTPS? (Y/N):");
if(Console.ReadLine().Trim().ToLower()=="y" ) var readLine = Console.ReadLine();
if (readLine != null && readLine.Trim().ToLower() == "y")
{ {
controller.EnableSSL = true; Controller.EnableSsl = true;
} }
Console.Write("Do you want to set this as a System Proxy? (Y/N):"); Console.Write("Do you want to set this as a System Proxy? (Y/N):");
if (Console.ReadLine().Trim().ToLower() == "y") var line = Console.ReadLine();
if (line != null && line.Trim().ToLower() == "y")
{ {
controller.SetAsSystemProxy = true; Controller.SetAsSystemProxy = true;
} }
controller.Visited += PageVisited;
//Start proxy controller //Start proxy controller
controller.StartProxy(); Controller.StartProxy();
Console.WriteLine("Hit any key to exit.."); Console.WriteLine("Hit any key to exit..");
Console.WriteLine(); Console.WriteLine();
Console.Read(); Console.Read();
controller.Stop(); Controller.Stop();
} }
private static void PageVisited(VisitedEventArgs e)
{ private static bool ConsoleEventCallback(int eventType)
Console.WriteLine(string.Concat("Visited: ", e.URL));
}
static bool ConsoleEventCallback(int eventType)
{
if (eventType == 2)
{ {
if (eventType != 2) return false;
try try
{ {
controller.Stop(); Controller.Stop();
} }
catch { } catch
{
// ignored
} }
return false; return false;
} }
// Keeps it from getting garbage collected }
private static ConsoleEventDelegate handler;
// Pinvoke
private delegate bool ConsoleEventDelegate(int eventType);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
internal static class NativeMethods
{
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
// Pinvoke
internal delegate bool ConsoleEventDelegate(int eventType);
} }
} }
\ No newline at end of file
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("Demo")] [assembly: AssemblyTitle("Demo")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
...@@ -17,9 +17,11 @@ using System.Runtime.InteropServices; ...@@ -17,9 +17,11 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible // 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 // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("33a2109d-0312-4c94-aa51-fbb2a83e63ab")] [assembly: Guid("33a2109d-0312-4c94-aa51-fbb2a83e63ab")]
// Version information for an assembly consists of the following four values: // Version information for an assembly consists of the following four values:
...@@ -32,5 +34,6 @@ using System.Runtime.InteropServices; ...@@ -32,5 +34,6 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using Titanium.Web.Proxy.EventArguments;
using System.Linq;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
using System.DirectoryServices.AccountManagement;
using System.DirectoryServices.ActiveDirectory;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Test namespace Titanium.Web.Proxy.Test
{ {
public partial class ProxyTestController public class ProxyTestController
{ {
private List<string> _URLList = new List<string>();
private string _lastURL = string.Empty;
public int ListeningPort { get; set; } public int ListeningPort { get; set; }
public bool EnableSSL { get; set; } public bool EnableSsl { get; set; }
public bool SetAsSystemProxy { get; set; } public bool SetAsSystemProxy { get; set; }
public void StartProxy() public void StartProxy()
{
if(Visited!=null)
{ {
ProxyServer.BeforeRequest += OnRequest; ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; ProxyServer.BeforeResponse += OnResponse;
}
ProxyServer.EnableSSL = EnableSSL; ProxyServer.EnableSsl = EnableSsl;
ProxyServer.SetAsSystemProxy = SetAsSystemProxy; ProxyServer.SetAsSystemProxy = SetAsSystemProxy;
//Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning
//for example dropbox.com
ProxyServer.ExcludedHttpsHostNameRegex.Add(".dropbox.com");
ProxyServer.Start(); ProxyServer.Start();
ProxyServer.ListeningPort = ProxyServer.ListeningPort;
ListeningPort = ProxyServer.ListeningPort; Console.WriteLine("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort);
Console.WriteLine(String.Format("Proxy listening on local machine port: {0} ", ProxyServer.ListeningPort));
} }
public void Stop() public void Stop()
{
if (Visited!=null)
{ {
ProxyServer.BeforeRequest -= OnRequest; ProxyServer.BeforeRequest -= OnRequest;
ProxyServer.BeforeResponse -= OnResponse; ProxyServer.BeforeResponse -= OnResponse;
}
ProxyServer.Stop(); ProxyServer.Stop();
} }
public delegate void SiteVisitedEventHandler(VisitedEventArgs e);
public event SiteVisitedEventHandler Visited;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(VisitedEventArgs e)
{
if (Visited != null)
Visited(e);
}
//Test On Request, intecept requests //Test On Request, intecept requests
//Read browser URL send back to proxy by the injection script in OnResponse event //Read browser URL send back to proxy by the injection script in OnResponse event
public void OnRequest(object sender, SessionEventArgs e) public void OnRequest(object sender, SessionEventArgs e)
{ {
string Random = e.RequestURL.Substring(e.RequestURL.LastIndexOf(@"/") + 1); Console.WriteLine(e.RequestUrl);
int index = _URLList.IndexOf(Random);
if (index >= 0)
{
string URL = e.GetRequestHtmlBody(); ////read request headers
//var requestHeaders = e.RequestHeaders;
if (_lastURL != URL) //if ((e.RequestMethod.ToUpper() == "POST" || e.RequestMethod.ToUpper() == "PUT"))
{ //{
OnChanged(new VisitedEventArgs() { hostname = e.RequestHostname, URL = URL, remoteIP = e.ClientIpAddress, remotePort = e.ClientPort }); // //Get/Set request body bytes
// byte[] bodyBytes = e.GetRequestBody();
// e.SetRequestBody(bodyBytes);
} // //Get/Set request body as string
// string bodyString = e.GetRequestBodyAsString();
// e.SetRequestBodyString(bodyString);
e.Ok(null); //}
_lastURL = URL;
} ////To cancel a request with a custom HTML content
////Filter URL
//if (e.RequestURL.Contains("google.com"))
//{
// e.Ok("<!DOCTYPE html><html><body><h1>Website Blocked</h1><p>Blocked by titanium web proxy.</p></body></html>");
//}
} }
//Test script injection //Test script injection
//Insert script to read the Browser URL and send it back to proxy //Insert script to read the Browser URL and send it back to proxy
public void OnResponse(object sender, SessionEventArgs e) public void OnResponse(object sender, SessionEventArgs e)
{ {
try ////read response headers
{ //var responseHeaders = e.ResponseHeaders;
if (e.ProxyRequest.Method == "GET" || e.ProxyRequest.Method == "POST") //if (e.ResponseStatusCode == HttpStatusCode.OK)
{ //{
if (e.ServerResponse.StatusCode == HttpStatusCode.OK) // if (e.ResponseContentType.Trim().ToLower().Contains("text/html"))
{ // {
if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html")) // //Get/Set response body bytes
{ // byte[] responseBodyBytes = e.GetResponseBody();
string c = e.ServerResponse.GetResponseHeader("X-Requested-With"); // e.SetResponseBody(responseBodyBytes);
if (e.ServerResponse.GetResponseHeader("X-Requested-With") == "")
{
string responseHtmlBody = e.GetResponseHtmlBody();
string functioname = "fr" + RandomString(10);
string VisitedURL = RandomString(5);
string RequestVariable = "c" + RandomString(5);
string RandomURLEnding = RandomString(25);
string RandomLastRequest = RandomString(10);
string LocalRequest;
if (e.IsSSLRequest)
LocalRequest = "https://" + e.RequestHostname + "/" + RandomURLEnding;
else
LocalRequest = "http://" + e.RequestHostname + "/" + RandomURLEnding;
string script = "var " + RandomLastRequest + " = null;" +
"if(window.top==self) { " + "\n" +
" " + functioname + "();" +
"setInterval(" + functioname + ",500); " + "\n" + "}" +
"function " + functioname + "(){ " + "\n" +
"var " + RequestVariable + " = new XMLHttpRequest(); " + "\n" +
"var " + VisitedURL + " = null;" + "\n" +
"if(window.top.location.href!=null) " + "\n" +
"" + VisitedURL + " = window.top.location.href; else " + "\n" +
"" + VisitedURL + " = document.referrer; " +
"if(" + RandomLastRequest + "!= " + VisitedURL + ") {" +
RequestVariable + ".open(\"POST\",\"" + LocalRequest + "\", true); " + "\n" +
RequestVariable + ".send(" + VisitedURL + ");} " + RandomLastRequest + " = " + VisitedURL + "}";
Regex RE = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string modifiedResponseHtmlBody = RE.Replace(responseHtmlBody, "<script type =\"text/javascript\">" + script + "</script></body>", 1);
if (modifiedResponseHtmlBody.Length != responseHtmlBody.Length)
{
e.SetResponseHtmlBody(modifiedResponseHtmlBody);
_URLList.Add(RandomURLEnding);
}
}
}
}
}
}
catch { }
// //Get response body as string
// string responseBody = e.GetResponseBodyAsString();
} // //Modify e.ServerResponse
// Regex rex = new Regex("</body>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline);
// string modified = rex.Replace(responseBody, "<script type =\"text/javascript\">alert('Response was modified by this script!');</script></body>", 1);
private Random random = new Random((int)DateTime.Now.Ticks);
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString(); // //Set modifed response Html Body
// e.SetResponseBodyString(modified);
// }
//}
} }
}
public class VisitedEventArgs : EventArgs
{
public string URL;
public string hostname;
public IPAddress remoteIP { get; set; }
public int remotePort { get; set; }
} }
} }
\ No newline at end of file
...@@ -16,6 +16,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B8 ...@@ -16,6 +16,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6FD3B8
.nuget\NuGet.targets = .nuget\NuGet.targets .nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -46,12 +52,30 @@ Global ...@@ -46,12 +52,30 @@ Global
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x64.Build.0 = 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.ActiveCfg = Release|x86
{8D73A1BE-868C-42D2-9ECE-F32CC1A02906}.Release|x86.Build.0 = 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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{F3B7E553-1904-4E80-BDC7-212342B5C952} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
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;
namespace Titanium.Web.Proxy.EventArguments
{
public class SessionEventArgs : EventArgs, IDisposable
{
readonly int _bufferSize;
internal SessionEventArgs(int bufferSize)
{
_bufferSize = bufferSize;
}
internal TcpClient Client { get; set; }
internal Stream ClientStream { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
public bool IsHttps { get; internal set; }
public string RequestUrl { get; internal set; }
public string RequestHostname { get; internal set; }
public int ClientPort { get; internal set; }
public IPAddress ClientIpAddress { get; internal set; }
internal Encoding RequestEncoding { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal byte[] RequestBody { get; set; }
internal string RequestBodyString { get; set; }
internal bool RequestBodyRead { get; set; }
public List<HttpHeader> RequestHeaders { get; internal set; }
internal bool RequestLocked { get; set; }
internal HttpClient ProxyRequest { get; set; }
internal Encoding ResponseEncoding { get; set; }
internal Stream ResponseStream { get; set; }
internal byte[] ResponseBody { get; set; }
internal string ResponseBodyString { get; set; }
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
{
get
{
if (RequestHeaders.All(x => x.Name.ToLower() != "content-length")) return -1;
int contentLen;
int.TryParse(RequestHeaders.First(x => x.Name.ToLower() == "content-length").Value, out contentLen);
if (contentLen != 0)
return contentLen;
return -1;
}
}
public string RequestMethod
{
get { return ProxyRequest.Method; }
}
public HttpStatusCode ResponseStatusCode
{
get { return ProxyRequest.StatusCode; }
}
public string ResponseContentType
{
get
{
return ResponseHeaders.Any(x => x.Name.ToLower() == "content-type")
? ResponseHeaders.First(x => x.Name.ToLower() == "content-type").Value
: null;
}
}
public void Dispose()
{
if (ProxyRequest != null)
ProxyRequest.Abort();
if (ResponseStream != null)
ResponseStream.Dispose();
if (ProxyRequest != null)
ProxyRequest.Close();
}
private void ReadRequestBody()
{
if ((ProxyRequest.Method.ToUpper() != "POST" && ProxyRequest.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.");
}
if (RequestBody == null)
{
var isChunked = false;
string requestContentEncoding = null;
if (RequestHeaders.Any(x => x.Name.ToLower() == "content-encoding"))
{
requestContentEncoding = RequestHeaders.First(x => x.Name.ToLower() == "content-encoding").Value;
}
if (RequestHeaders.Any(x => x.Name.ToLower() == "transfer-encoding"))
{
var transferEncoding =
RequestHeaders.First(x => x.Name.ToLower() == "transfer-encoding").Value.ToLower();
if (transferEncoding.Contains("chunked"))
{
isChunked = true;
}
}
if (requestContentEncoding == null && !isChunked)
RequestBody = ClientStreamReader.ReadBytes(RequestContentLength);
else
{
using (var requestBodyStream = new MemoryStream())
{
if (isChunked)
{
while (true)
{
var chuchkHead = ClientStreamReader.ReadLine();
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
if (chunkSize != 0)
{
var buffer = ClientStreamReader.ReadBytes(chunkSize);
requestBodyStream.Write(buffer, 0, buffer.Length);
//chunk trail
ClientStreamReader.ReadLine();
}
else
{
ClientStreamReader.ReadLine();
break;
}
}
}
try
{
switch (requestContentEncoding)
{
case "gzip":
RequestBody = CompressionHelper.DecompressGzip(requestBodyStream);
break;
case "deflate":
RequestBody = CompressionHelper.DecompressDeflate(requestBodyStream);
break;
case "zlib":
RequestBody = CompressionHelper.DecompressGzip(requestBodyStream);
break;
default:
RequestBody = requestBodyStream.ToArray();
break;
}
}
catch
{
RequestBody = requestBodyStream.ToArray();
}
}
}
}
RequestBodyRead = true;
}
private void ReadResponseBody()
{
if (ResponseBody == null)
{
switch (ProxyRequest.ContentEncoding)
{
case "gzip":
ResponseBody = CompressionHelper.DecompressGzip(ResponseStream);
break;
case "deflate":
ResponseBody = CompressionHelper.DecompressDeflate(ResponseStream);
break;
case "zlib":
ResponseBody = CompressionHelper.DecompressZlib(ResponseStream);
break;
default:
ResponseBody = DecodeData(ResponseStream);
break;
}
ResponseBodyRead = true;
}
}
//stream reader not recomended for images
private byte[] DecodeData(Stream responseStream)
{
var buffer = new byte[_bufferSize];
using (var ms = new MemoryStream())
{
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
public Encoding GetRequestBodyEncoding()
{
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
return RequestEncoding;
}
public byte[] GetRequestBody()
{
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody();
return RequestBody;
}
public string GetRequestBodyAsString()
{
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
ReadRequestBody();
return RequestBodyString ?? (RequestBodyString = RequestEncoding.GetString(RequestBody));
}
public void SetRequestBody(byte[] body)
{
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (!RequestBodyRead)
{
ReadRequestBody();
}
RequestBody = body;
RequestBodyRead = true;
}
public void SetRequestBodyString(string body)
{
if (RequestLocked) throw new Exception("Youcannot call this function after request is made to server.");
if (!RequestBodyRead)
{
ReadRequestBody();
}
RequestBody = RequestEncoding.GetBytes(body);
RequestBodyRead = true;
}
public Encoding GetResponseBodyEncoding()
{
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
return ResponseEncoding;
}
public byte[] GetResponseBody()
{
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
ReadResponseBody();
return ResponseBody;
}
public string GetResponseBodyAsString()
{
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
GetResponseBody();
return ResponseBodyString ?? (ResponseBodyString = ResponseEncoding.GetString(ResponseBody));
}
public void SetResponseBody(byte[] body)
{
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
if (ResponseBody == null)
{
GetResponseBody();
}
ResponseBody = body;
}
public void SetResponseBodyString(string body)
{
if (!RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
if (ResponseBody == null)
{
GetResponseBody();
}
var bodyBytes = ResponseEncoding.GetBytes(body);
SetResponseBody(bodyBytes);
}
public void Ok(string html)
{
if (RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
if (html == null)
html = string.Empty;
var result = Encoding.Default.GetBytes(html);
var connectStreamWriter = new StreamWriter(ClientStream);
var s = string.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok");
connectStreamWriter.WriteLine(s);
connectStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
connectStreamWriter.WriteLine("content-length: " + result.Length);
connectStreamWriter.WriteLine("Cache-Control: no-cache, no-store, must-revalidate");
connectStreamWriter.WriteLine("Pragma: no-cache");
connectStreamWriter.WriteLine("Expires: 0");
connectStreamWriter.WriteLine(RequestIsAlive ? "Connection: Keep-Alive" : "Connection: close");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
ClientStream.Write(result, 0, result.Length);
CancelRequest = true;
}
}
}
\ No newline at end of file
using System;
namespace Titanium.Web.Proxy.Exceptions
{
public class BodyNotFoundException : Exception
{
public BodyNotFoundException(string message)
: base(message)
{
}
}
}
\ No newline at end of file
using System.Net;
using System.Text;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebRequestExtensions
{
public static Encoding GetEncoding(this HttpWebRequest request)
{
try
{
if (request.ContentType == null) return Encoding.GetEncoding("ISO-8859-1");
var contentTypes = request.ContentType.Split(';');
foreach (var contentType in contentTypes)
{
var encodingSplit = contentType.Split('=');
if (encodingSplit.Length == 2 && encodingSplit[0].ToLower().Trim() == "charset")
{
return Encoding.GetEncoding(encodingSplit[1]);
}
}
}
catch
{
// ignored
}
return Encoding.GetEncoding("ISO-8859-1");
}
}
}
\ No newline at end of file
using System.Net;
using System.Text;
namespace Titanium.Web.Proxy.Extensions
{
public static class HttpWebResponseExtensions
{
public static Encoding GetEncoding(this HttpWebResponse response)
{
if (string.IsNullOrEmpty(response.CharacterSet)) return Encoding.GetEncoding("ISO-8859-1");
return Encoding.GetEncoding(response.CharacterSet.Replace(@"""",string.Empty));
}
}
}
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO; using System.IO;
using System.Text;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Extensions
{ {
public static class StreamHelper public static class StreamHelper
{ {
private const int DEFAULT_BUFFER_SIZE = 8192; // +32767 public static void CopyToAsync(this Stream input, string initialData, Stream output, int bufferSize)
public static void CopyTo(this Stream input, Stream output)
{
input.CopyTo(output, DEFAULT_BUFFER_SIZE);
return;
}
public static void CopyTo(string initialData, Stream input, Stream output, int bufferSize)
{ {
var bytes = Encoding.ASCII.GetBytes(initialData); var bytes = Encoding.ASCII.GetBytes(initialData);
output.Write(bytes,0, bytes.Length); output.Write(bytes, 0, bytes.Length);
CopyTo(input, output, bufferSize); CopyToAsync(input, output, bufferSize);
} }
public static void CopyTo(this Stream input, Stream output, int bufferSize)
//http://stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write
public static void CopyToAsync(this Stream input, Stream output, int bufferSize)
{ {
try try
{ {
if (!input.CanRead) throw new InvalidOperationException("input must be open for reading"); if (!input.CanRead) throw new InvalidOperationException("input must be open for reading");
if (!output.CanWrite) throw new InvalidOperationException("output must be open for writing"); if (!output.CanWrite) throw new InvalidOperationException("output must be open for writing");
byte[][] buf = { new byte[bufferSize], new byte[bufferSize] }; byte[][] buf = {new byte[bufferSize], new byte[bufferSize]};
int[] bufl = { 0, 0 }; int[] bufl = {0, 0};
int bufno = 0; var bufno = 0;
IAsyncResult read = input.BeginRead(buf[bufno], 0, buf[bufno].Length, null, null); var read = input.BeginRead(buf[bufno], 0, buf[bufno].Length, null, null);
IAsyncResult write = null; IAsyncResult write = null;
while (true) while (true)
{ {
// wait for the read operation to complete // wait for the read operation to complete
read.AsyncWaitHandle.WaitOne(); read.AsyncWaitHandle.WaitOne();
bufl[bufno] = input.EndRead(read); bufl[bufno] = input.EndRead(read);
...@@ -66,7 +57,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -66,7 +57,6 @@ namespace Titanium.Web.Proxy.Helpers
// A little speedier than using a ternary expression. // A little speedier than using a ternary expression.
bufno ^= 1; // bufno = ( bufno == 0 ? 1 : 0 ) ; bufno ^= 1; // bufno = ( bufno == 0 ? 1 : 0 ) ;
read = input.BeginRead(buf[bufno], 0, buf[bufno].Length, null, null); read = input.BeginRead(buf[bufno], 0, buf[bufno].Length, null, null);
} }
// wait for the final in-flight write operation, if one exists, to complete // wait for the final in-flight write operation, if one exists, to complete
...@@ -79,9 +69,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -79,9 +69,11 @@ namespace Titanium.Web.Proxy.Helpers
output.Flush(); output.Flush();
} }
catch { } catch
{
// ignored
}
// return to the caller ; // return to the caller ;
return;
} }
} }
} }
\ No newline at end of file
...@@ -6,10 +6,10 @@ using System.Security.Cryptography.X509Certificates; ...@@ -6,10 +6,10 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public class CertificateManager public class CertificateManager : IDisposable
{ {
private const string CERT_CREATE_FORMAT = private const string CertCreateFormat =
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 -b {5:MM/dd/yyyy} {6}"; "-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 {5}";
private readonly IDictionary<string, X509Certificate2> _certificateCache; private readonly IDictionary<string, X509Certificate2> _certificateCache;
...@@ -69,6 +69,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -69,6 +69,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName) protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName)
{ {
if (_certificateCache.ContainsKey(certificateName)) if (_certificateCache.ContainsKey(certificateName))
return _certificateCache[certificateName]; return _certificateCache[certificateName];
...@@ -80,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -80,7 +81,7 @@ namespace Titanium.Web.Proxy.Helpers
store.Open(OpenFlags.ReadWrite); store.Open(OpenFlags.ReadWrite);
string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer); string certificateSubject = string.Format("CN={0}, O={1}", certificateName, Issuer);
X509Certificate2Collection certificates = var certificates =
FindCertificates(store, certificateSubject); FindCertificates(store, certificateSubject);
if (certificates != null) if (certificates != null)
...@@ -164,13 +165,22 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -164,13 +165,22 @@ namespace Titanium.Web.Proxy.Helpers
bool isRootCertificate = bool isRootCertificate =
(certificateName == RootCertificateName); (certificateName == RootCertificateName);
string certCreatArgs = string.Format(CERT_CREATE_FORMAT, string certCreatArgs = string.Format(CertCreateFormat,
store.Name, certificateName, Issuer, store.Name, certificateName, Issuer,
isRootCertificate ? "signature" : "exchange", isRootCertificate ? "signature" : "exchange",
isRootCertificate ? "authority" : "end", DateTime.Now, isRootCertificate ? "authority" : "end",
isRootCertificate ? "-h 1 -r" : string.Format("-pe -in \"{0}\" -is Root", RootCertificateName)); isRootCertificate ? "-h 1 -r" : string.Format("-pe -in \"{0}\" -is Root", RootCertificateName));
return certCreatArgs; return certCreatArgs;
} }
public void Dispose()
{
if (MyStore != null)
MyStore.Close();
if (RootStore != null)
RootStore.Close();
}
} }
} }
\ No newline at end of file
using System; using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO; using System.IO;
using Ionic.Zlib;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public class CompressionHelper public class CompressionHelper
{ {
private static readonly int BUFFER_SIZE = 8192; private const int BufferSize = 8192;
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static string DecompressGzip(Stream input, Encoding e) public static byte[] CompressZlib(byte[] bytes)
{ {
using (System.IO.Compression.GZipStream decompressor = new System.IO.Compression.GZipStream(input, System.IO.Compression.CompressionMode.Decompress)) using (var ms = new MemoryStream())
{ {
using (var zip = new ZlibStream(ms, CompressionMode.Compress, true))
int read = 0;
var buffer = new byte[BUFFER_SIZE];
using (MemoryStream output = new MemoryStream())
{
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{ {
output.Write(buffer, 0, read); zip.Write(bytes, 0, bytes.Length);
}
return e.GetString(output.ToArray());
} }
return ms.ToArray();
} }
} }
public static byte[] CompressZlib(string ResponseData, Encoding e) [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressDeflate(byte[] bytes)
{ {
using (var ms = new MemoryStream())
Byte[] bytes = e.GetBytes(ResponseData);
using (MemoryStream ms = new MemoryStream())
{ {
using (var zip = new DeflateStream(ms, CompressionMode.Compress, true))
using (Ionic.Zlib.ZlibStream zip = new Ionic.Zlib.ZlibStream(ms, Ionic.Zlib.CompressionMode.Compress, true))
{ {
zip.Write(bytes, 0, bytes.Length); zip.Write(bytes, 0, bytes.Length);
} }
return ms.ToArray(); return ms.ToArray();
} }
} }
public static byte[] CompressDeflate(string ResponseData, Encoding e) [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressGzip(byte[] bytes)
{ {
Byte[] bytes = e.GetBytes(ResponseData); using (var ms = new MemoryStream())
using (MemoryStream ms = new MemoryStream())
{ {
using (var zip = new GZipStream(ms, CompressionMode.Compress, true))
using (Ionic.Zlib.DeflateStream zip = new Ionic.Zlib.DeflateStream(ms, Ionic.Zlib.CompressionMode.Compress, true))
{ {
zip.Write(bytes, 0, bytes.Length); zip.Write(bytes, 0, bytes.Length);
} }
return ms.ToArray(); return ms.ToArray();
} }
} }
public static byte[] CompressGzip(string ResponseData, Encoding e) public static byte[] DecompressGzip(Stream input)
{
using (
var decompressor = new System.IO.Compression.GZipStream(input,
System.IO.Compression.CompressionMode.Decompress))
{ {
Byte[] bytes = e.GetBytes(ResponseData); var buffer = new byte[BufferSize];
using (MemoryStream ms = new MemoryStream()) using (var output = new MemoryStream())
{ {
using (Ionic.Zlib.GZipStream zip = new Ionic.Zlib.GZipStream(ms, Ionic.Zlib.CompressionMode.Compress, true)) int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{ {
zip.Write(bytes, 0, bytes.Length); output.Write(buffer, 0, read);
}
return output.ToArray();
} }
return ms.ToArray();
} }
} }
public static string DecompressDeflate(Stream input, Encoding e)
{
using (Ionic.Zlib.DeflateStream decompressor = new Ionic.Zlib.DeflateStream(input, Ionic.Zlib.CompressionMode.Decompress)) public static byte[] DecompressDeflate(Stream input)
{ {
int read = 0; using (var decompressor = new DeflateStream(input, CompressionMode.Decompress))
var buffer = new byte[BUFFER_SIZE]; {
var buffer = new byte[BufferSize];
using (MemoryStream output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0) while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{ {
output.Write(buffer, 0, read); output.Write(buffer, 0, read);
} }
return e.GetString(output.ToArray()); return output.ToArray();
} }
} }
} }
public static string DecompressZlib(Stream input, Encoding e)
{
using (Ionic.Zlib.ZlibStream decompressor = new Ionic.Zlib.ZlibStream(input, Ionic.Zlib.CompressionMode.Decompress)) public static byte[] DecompressZlib(Stream input)
{ {
using (var decompressor = new ZlibStream(input, CompressionMode.Decompress))
{
var buffer = new byte[BufferSize];
int read = 0; using (var output = new MemoryStream())
var buffer = new byte[BUFFER_SIZE];
using (MemoryStream output = new MemoryStream())
{ {
int read;
while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0) while ((read = decompressor.Read(buffer, 0, buffer.Length)) > 0)
{ {
output.Write(buffer, 0, read); output.Write(buffer, 0, read);
} }
return e.GetString(output.ToArray()); return output.ToArray();
} }
} }
} }
} }
} }
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace Titanium.Web.Proxy.Helpers
{
public class CustomBinaryReader : BinaryReader
{
public CustomBinaryReader(Stream stream, Encoding encoding)
: base(stream, encoding)
{
}
public string ReadLine()
{
char[] buf = new char[1];
StringBuilder _readBuffer = new StringBuilder();
try
{
var charsRead = 0;
char lastChar = new char();
while ((charsRead = base.Read(buf, 0, 1)) > 0)
{
if (lastChar == '\r' && buf[0] == '\n')
{
return _readBuffer.Remove(_readBuffer.Length - 1, 1).ToString();
}
else
if (buf[0] == '\0')
{
return _readBuffer.ToString();
}
else
_readBuffer.Append(buf[0]);
lastChar = buf[0];
}
return _readBuffer.ToString();
}
catch (IOException)
{ return _readBuffer.ToString(); }
catch (Exception e)
{ throw e; }
}
}
}
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO; using System.IO;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
...@@ -12,21 +9,23 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -12,21 +9,23 @@ namespace Titanium.Web.Proxy.Helpers
{ {
try try
{ {
DirectoryInfo[] myProfileDirectory = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default"); var myProfileDirectory =
string myFFPrefFile = myProfileDirectory[0].FullName + "\\prefs.js"; new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
if (File.Exists(myFFPrefFile)) "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default");
var myFfPrefFile = myProfileDirectory[0].FullName + "\\prefs.js";
if (File.Exists(myFfPrefFile))
{ {
// We have a pref file so let''s make sure it has the proxy setting // We have a pref file so let''s make sure it has the proxy setting
StreamReader myReader = new StreamReader(myFFPrefFile); var myReader = new StreamReader(myFfPrefFile);
string myPrefContents = myReader.ReadToEnd(); var myPrefContents = myReader.ReadToEnd();
myReader.Close(); myReader.Close();
if (myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) if (myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);"))
{ {
// Add the proxy enable line and write it back to the file // Add the proxy enable line and write it back to the file
myPrefContents = myPrefContents.Replace("user_pref(\"network.proxy.type\", 0);", ""); myPrefContents = myPrefContents.Replace("user_pref(\"network.proxy.type\", 0);", "");
File.Delete(myFFPrefFile); File.Delete(myFfPrefFile);
File.WriteAllText(myFFPrefFile, myPrefContents); File.WriteAllText(myFfPrefFile, myPrefContents);
} }
} }
} }
...@@ -35,25 +34,28 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -35,25 +34,28 @@ namespace Titanium.Web.Proxy.Helpers
// Only exception should be a read/write error because the user opened up FireFox so they can be ignored. // Only exception should be a read/write error because the user opened up FireFox so they can be ignored.
} }
} }
public static void RemoveFirefox() public static void RemoveFirefox()
{ {
try try
{ {
DirectoryInfo[] myProfileDirectory = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default"); var myProfileDirectory =
string myFFPrefFile = myProfileDirectory[0].FullName + "\\prefs.js"; new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
if (File.Exists(myFFPrefFile)) "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default");
var myFfPrefFile = myProfileDirectory[0].FullName + "\\prefs.js";
if (File.Exists(myFfPrefFile))
{ {
// We have a pref file so let''s make sure it has the proxy setting // We have a pref file so let''s make sure it has the proxy setting
StreamReader myReader = new StreamReader(myFFPrefFile); var myReader = new StreamReader(myFfPrefFile);
string myPrefContents = myReader.ReadToEnd(); var myPrefContents = myReader.ReadToEnd();
myReader.Close(); myReader.Close();
if (!myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) if (!myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);"))
{ {
// Add the proxy enable line and write it back to the file // Add the proxy enable line and write it back to the file
myPrefContents = myPrefContents + "\n\r" + "user_pref(\"network.proxy.type\", 0);"; myPrefContents = myPrefContents + "\n\r" + "user_pref(\"network.proxy.type\", 0);";
File.Delete(myFFPrefFile); File.Delete(myFfPrefFile);
File.WriteAllText(myFFPrefFile, myPrefContents); File.WriteAllText(myFfPrefFile, myPrefContents);
} }
} }
} }
......
using System; using System;
using System.Collections.Generic; using System.Net.Configuration;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public class NetFrameworkHelper public class NetFrameworkHelper
{ {
public static void URLPeriodFix() //Fix bug in .Net 4.0 HttpWebRequest (don't use this for 4.5 and above)
//http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end
public static void UrlPeriodFix()
{ {
MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); var getSyntax = typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
FieldInfo flagsField = typeof(UriParser).GetField("m_Flags", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var flagsField = typeof (UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
if (getSyntax != null && flagsField != null) if (getSyntax != null && flagsField != null)
{ {
foreach (string scheme in new[] { "http", "https" }) foreach (var scheme in new[] {"http", "https"})
{ {
UriParser parser = (UriParser)getSyntax.Invoke(null, new object[] { scheme }); var parser = (UriParser) getSyntax.Invoke(null, new object[] {scheme});
if (parser != null) if (parser != null)
{ {
int flagsValue = (int)flagsField.GetValue(parser); var flagsValue = (int) flagsField.GetValue(parser);
if ((flagsValue & 0x1000000) != 0) if ((flagsValue & 0x1000000) != 0)
flagsField.SetValue(parser, flagsValue & ~0x1000000); flagsField.SetValue(parser, flagsValue & ~0x1000000);
} }
} }
} }
}
// Enable/disable useUnsafeHeaderParsing.
// See http://o2platform.wordpress.com/2010/10/20/dealing-with-the-server-committed-a-protocol-violation-sectionresponsestatusline/
public static bool ToggleAllowUnsafeHeaderParsing(bool enable)
{
//Get the assembly that contains the internal class
var assembly = Assembly.GetAssembly(typeof (SettingsSection));
if (assembly != null)
{
//Use the assembly in order to get the internal type for the internal class
var settingsSectionType = assembly.GetType("System.Net.Configuration.SettingsSectionInternal");
if (settingsSectionType != null)
{
//Use the internal static property to get an instance of the internal settings class.
//If the static instance isn't created already invoking the property will create it for us.
var anInstance = settingsSectionType.InvokeMember("Section",
BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null,
new object[] {});
if (anInstance != null)
{
//Locate the private bool field that tells the framework if unsafe header parsing is allowed
var aUseUnsafeHeaderParsing = settingsSectionType.GetField("useUnsafeHeaderParsing",
BindingFlags.NonPublic | BindingFlags.Instance);
if (aUseUnsafeHeaderParsing != null)
{
aUseUnsafeHeaderParsing.SetValue(anInstance, enable);
return true;
}
}
}
}
return false;
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public static class SystemProxyHelper internal static class NativeMethods
{ {
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
public const int INTERNET_OPTION_SETTINGS_CHANGED = 39; int dwBufferLength);
public const int INTERNET_OPTION_REFRESH = 37; }
static bool settingsReturn, refreshReturn;
static object prevProxyServer;
static object prevProxyEnable;
public static void EnableProxyHTTP(string hostname, int port) public static class SystemProxyHelper
{
public const int InternetOptionSettingsChanged = 39;
public const int InternetOptionRefresh = 37;
private static object _prevProxyServer;
private static object _prevProxyEnable;
public static void EnableProxyHttp(string hostname, int port)
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null)
{ {
RegistryKey reg = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); _prevProxyEnable = reg.GetValue("ProxyEnable");
prevProxyEnable = reg.GetValue("ProxyEnable"); _prevProxyServer = reg.GetValue("ProxyServer");
prevProxyServer = reg.GetValue("ProxyServer");
reg.SetValue("ProxyEnable", 1); reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", "http="+hostname+":" + port + ";"); reg.SetValue("ProxyServer", "http=" + hostname + ":" + port + ";");
refresh();
} }
public static void EnableProxyHTTPS(string hostname, int port) Refresh();
}
public static void EnableProxyHttps(string hostname, int port)
{
var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null)
{ {
RegistryKey reg = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
reg.SetValue("ProxyEnable", 1); reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", "http=" + hostname + ":" + port + ";https=" + hostname + ":" + port); reg.SetValue("ProxyServer", "http=" + hostname + ":" + port + ";https=" + hostname + ":" + port);
refresh();
} }
Refresh();
}
public static void DisableAllProxy() public static void DisableAllProxy()
{ {
RegistryKey reg = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); var reg = Registry.CurrentUser.OpenSubKey(
reg.SetValue("ProxyEnable", prevProxyEnable); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (prevProxyServer != null) if (reg != null)
reg.SetValue("ProxyServer", prevProxyServer); {
refresh(); reg.SetValue("ProxyEnable", _prevProxyEnable);
if (_prevProxyServer != null)
reg.SetValue("ProxyServer", _prevProxyServer);
} }
private static void refresh() Refresh();
}
private static void Refresh()
{ {
settingsReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero,0);
refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Net.Security; using System.Net.Security;
using System.IO; using System.Net.Sockets;
using System.Net; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Http;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public class TcpHelper public class TcpHelper
{ {
private static readonly int BUFFER_SIZE = 8192; private static readonly int BUFFER_SIZE = 8192;
private static readonly String[] colonSpaceSplit = new string[] { ": " };
public static void SendRaw(string Hostname, int TunnelPort, System.IO.Stream ClientStream)
{
System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(Hostname, TunnelPort);
var tunnelStream = tunnelClient.GetStream();
var tunnelReadBuffer = new byte[BUFFER_SIZE];
Task sendRelay = new Task(() => StreamHelper.CopyTo(ClientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay);
if (tunnelStream != null) public static void SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
tunnelStream.Close(); int tunnelPort, bool isHttps)
if (tunnelClient != null)
tunnelClient.Close();
}
public static void SendRaw(string HttpCmd, string SecureHostName, ref List<string> RequestLines, bool IsHttps, Stream ClientStream)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = null;
sb.Append(HttpCmd); if (httpCmd != null || requestHeaders != null)
sb.Append(Environment.NewLine);
string hostname = SecureHostName;
for (int i = 1; i < RequestLines.Count; i++)
{
var header = RequestLines[i];
if (SecureHostName == null)
{ {
String[] headerParsed = HttpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None); sb = new StringBuilder();
switch (headerParsed[0].ToLower()) if (httpCmd != null)
{ {
case "host": sb.Append(httpCmd);
var hostdetail = headerParsed[1]; sb.Append(Environment.NewLine);
if (hostdetail.Contains(":"))
hostname = hostdetail.Split(':')[0].Trim();
else
hostname = hostdetail.Trim();
break;
default:
break;
}
} }
if (requestHeaders != null)
foreach (var header in requestHeaders.Select(t => t.ToString()))
{
sb.Append(header); sb.Append(header);
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
} }
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
}
int tunnelPort = 80;
if (IsHttps)
{
tunnelPort = 443;
} TcpClient tunnelClient = null;
Stream tunnelStream = null;
System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort); try
var tunnelStream = tunnelClient.GetStream() as System.IO.Stream; {
tunnelClient = new TcpClient(hostName, tunnelPort);
tunnelStream = tunnelClient.GetStream();
if (IsHttps) if (isHttps)
{ {
var sslStream = new SslStream(tunnelStream); SslStream sslStream = null;
sslStream.AuthenticateAsClient(hostname); try
{
sslStream = new SslStream(tunnelStream);
sslStream.AuthenticateAsClient(hostName);
tunnelStream = sslStream; tunnelStream = sslStream;
} }
catch
{
if (sslStream != null)
sslStream.Dispose();
throw;
}
}
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), ClientStream, tunnelStream, BUFFER_SIZE)); var sendRelay = Task.Factory.StartNew(() =>
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE)); {
if (sb != null)
clientStream.CopyToAsync(sb.ToString(), tunnelStream, BUFFER_SIZE);
else
clientStream.CopyToAsync(tunnelStream, BUFFER_SIZE);
});
sendRelay.Start(); var receiveRelay = Task.Factory.StartNew(() => tunnelStream.CopyToAsync(clientStream, BUFFER_SIZE));
receiveRelay.Start();
Task.WaitAll(sendRelay, receiveRelay); Task.WaitAll(sendRelay, receiveRelay);
}
catch
{
if (tunnelStream != null) if (tunnelStream != null)
{
tunnelStream.Close(); tunnelStream.Close();
tunnelStream.Dispose();
}
if (tunnelClient != null) if (tunnelClient != null)
tunnelClient.Close(); tunnelClient.Close();
throw;
}
} }
} }
} }
\ No newline at end of file
using System;
using System.Text;
using System.IO;
using System.Net;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Models
{
public class SessionEventArgs : EventArgs
{
public string RequestURL { get; set; }
public string RequestHostname { get; set; }
public bool IsSSLRequest { get; set; }
public int ClientPort { get; set; }
public IPAddress ClientIpAddress { get; set; }
public HttpWebRequest ProxyRequest { get; set; }
public HttpWebResponse ServerResponse { get; set; }
internal int BUFFER_SIZE;
internal int RequestLength { get; set; }
internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal Stream ClientStream { get; set; }
internal Stream ServerResponseStream { get; set; }
internal Encoding Encoding { get; set; }
internal bool RequestWasModified { get; set; }
internal bool ResponseWasModified { get; set; }
internal string UpgradeProtocol { get; set; }
internal string RequestHtmlBody { get; set; }
internal string ResponseHtmlBody { get; set; }
public SessionEventArgs(int BufferSize)
{
BUFFER_SIZE = BufferSize;
}
public string GetRequestHtmlBody()
{
if (RequestHtmlBody == null)
{
int bytesRead;
int totalBytesRead = 0;
MemoryStream mw = new MemoryStream();
var buffer = ClientStreamReader.ReadBytes(RequestLength);
while (totalBytesRead < RequestLength && (bytesRead = buffer.Length) > 0)
{
totalBytesRead += bytesRead;
mw.Write(buffer, 0, bytesRead);
}
mw.Close();
RequestHtmlBody = Encoding.Default.GetString(mw.ToArray());
}
RequestWasModified = true;
return RequestHtmlBody;
}
public void SetRequestHtmlBody(string Body)
{
this.RequestHtmlBody = Body;
RequestWasModified = true;
}
public string GetResponseHtmlBody()
{
if (ResponseHtmlBody == null)
{
Encoding = Encoding.GetEncoding(ServerResponse.CharacterSet);
if (Encoding == null) Encoding = Encoding.Default;
string ResponseData = "";
switch (ServerResponse.ContentEncoding)
{
case "gzip":
ResponseData = CompressionHelper.DecompressGzip(ServerResponseStream, Encoding);
break;
case "deflate":
ResponseData = CompressionHelper.DecompressDeflate(ServerResponseStream, Encoding);
break;
case "zlib":
ResponseData = CompressionHelper.DecompressZlib(ServerResponseStream, Encoding);
break;
default:
ResponseData = DecodeData(ServerResponseStream, Encoding);
break;
}
ResponseHtmlBody = ResponseData;
ResponseWasModified = true;
}
return ResponseHtmlBody;
}
public void SetResponseHtmlBody(string Body)
{
this.ResponseHtmlBody = Body;
}
//stream reader not recomended for images
private string DecodeData(Stream ResponseStream, Encoding e)
{
StreamReader reader = new StreamReader(ResponseStream, e);
return reader.ReadToEnd();
}
public void Ok(string Html)
{
if (Html == null)
Html = string.Empty;
var result = Encoding.Default.GetBytes(Html);
StreamWriter connectStreamWriter = new StreamWriter(ClientStream);
var s = String.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok");
connectStreamWriter.WriteLine(s);
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("content-length: " + result.Length);
connectStreamWriter.WriteLine("Cache-Control: no-cache, no-store, must-revalidate");
connectStreamWriter.WriteLine("Pragma: no-cache");
connectStreamWriter.WriteLine("Expires: 0");
if (RequestIsAlive)
{
connectStreamWriter.WriteLine("Connection: Keep-Alive");
}
else
connectStreamWriter.WriteLine("Connection: close");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
ClientStream.Write(result, 0, result.Length);
CancelRequest = true;
}
public System.Net.Sockets.TcpClient Client { get; set; }
public string tunnelHostName { get; set; }
public string securehost { get; set; }
}
}
\ No newline at end of file
using System.Reflection;
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.Proxy.Properties")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy.Properties")]
[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("5036e0b7-a0d0-4070-8eb0-72c129dee9b3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.IO;
using System.Net; using System.Net;
using System.Net.Sockets;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication; using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Diagnostics; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
/// <summary> /// <summary>
...@@ -21,146 +17,134 @@ namespace Titanium.Web.Proxy ...@@ -21,146 +17,134 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public partial class ProxyServer public partial class ProxyServer
{ {
private static readonly int BUFFER_SIZE = 8192; private static readonly int BUFFER_SIZE = 8192;
private static readonly char[] semiSplit = new char[] { ';' }; private static readonly char[] SemiSplit = { ';' };
private static readonly String[] colonSpaceSplit = new string[] { ": " }; private static readonly string[] ColonSpaceSplit = { ": " };
private static readonly char[] spaceSplit = new char[] { ' ' }; private static readonly char[] SpaceSplit = { ' ' };
private static readonly Regex cookieSplitRegEx = new Regex(@",(?! )"); private static readonly Regex CookieSplitRegEx = new Regex(@",(?! )");
private static object certificateAccessLock = new object(); private static readonly byte[] ChunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine);
private static List<string> pinnedCertificateClients = new List<string>();
private static readonly byte[] ChunkEnd =
Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
private static TcpListener _listener;
private static TcpListener listener; public static List<string> ExcludedHttpsHostNameRegex = new List<string>();
private static Thread listenerThread;
public static event EventHandler<SessionEventArgs> BeforeRequest; static ProxyServer()
public static event EventHandler<SessionEventArgs> BeforeResponse; {
CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority");
ListeningIpAddress = IPAddress.Any;
ListeningPort = 0;
Initialize();
}
public static IPAddress ListeningIPInterface { get; set; } private static CertificateManager CertManager { get; set; }
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
public static bool EnableSSL { get; set; } public static bool EnableSsl { get; set; }
public static bool SetAsSystemProxy { get; set; } public static bool SetAsSystemProxy { get; set; }
public static Int32 ListeningPort public static int ListeningPort { get; set; }
{ public static IPAddress ListeningIpAddress { get; set; }
get
{
return ((IPEndPoint)listener.LocalEndpoint).Port;
}
}
public static CertificateManager CertManager { get; set; } public static event EventHandler<SessionEventArgs> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse;
static ProxyServer() public static void Initialize()
{
CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority");
}
public ProxyServer()
{ {
ServicePointManager.Expect100Continue = false;
WebRequest.DefaultWebProxy = null;
System.Net.ServicePointManager.Expect100Continue = false; ServicePointManager.DefaultConnectionLimit = 10;
System.Net.WebRequest.DefaultWebProxy = null; ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000; //3 minutes
System.Net.ServicePointManager.DefaultConnectionLimit = 10;
ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000;//3 minutes
ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000; ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000;
ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) //HttpWebRequest certificate validation callback
ServicePointManager.ServerCertificateValidationCallback =
delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{ {
if (sslPolicyErrors == SslPolicyErrors.None) return true; if (sslPolicyErrors == SslPolicyErrors.None) return true;
else
return false; return false;
}; };
NetFrameworkHelper.URLPeriodFix(); //Fix a bug in .NET 4.0
NetFrameworkHelper.UrlPeriodFix();
//useUnsafeHeaderParsing
NetFrameworkHelper.ToggleAllowUnsafeHeaderParsing(true);
} }
private static bool ShouldListen { get; set; }
public static bool Start() public static bool Start()
{ {
_listener = new TcpListener(ListeningIpAddress, ListeningPort);
_listener.Start();
listener = new TcpListener(IPAddress.Any, 0); ListeningPort = ((IPEndPoint)_listener.LocalEndpoint).Port;
listener.Start(); // accept clients asynchronously
listenerThread = new Thread(new ParameterizedThreadStart(Listen)); _listener.BeginAcceptTcpClient(OnAcceptConnection, _listener);
listenerThread.IsBackground = true;
ShouldListen = true; var certTrusted = false;
listenerThread.Start(listener);
if (EnableSsl)
certTrusted = CertManager.CreateTrustedRootCertificate();
if (SetAsSystemProxy) if (SetAsSystemProxy)
{ {
SystemProxyHelper.EnableProxyHTTP("localhost", ListeningPort); SystemProxyHelper.EnableProxyHttp(
Equals(ListeningIpAddress, IPAddress.Any) ? "127.0.0.1" : ListeningIpAddress.ToString(), ListeningPort);
FireFoxHelper.AddFirefox(); FireFoxHelper.AddFirefox();
if (EnableSSL) if (EnableSsl)
{ {
RootCertificateName = RootCertificateName == null ? "Titanium_Proxy_Test_Root" : RootCertificateName; RootCertificateName = RootCertificateName ?? "Titanium_Proxy_Test_Root";
bool certTrusted = CertManager.CreateTrustedRootCertificate(); //If certificate was trusted by the machine
if (!certTrusted) if (certTrusted)
{ {
// The user didn't want to install the self-signed certificate to the root store. SystemProxyHelper.EnableProxyHttps(
Equals(ListeningIpAddress, IPAddress.Any) ? "127.0.0.1" : ListeningIpAddress.ToString(),
ListeningPort);
} }
SystemProxyHelper.EnableProxyHTTPS("localhost", ListeningPort);
} }
} }
return true; return true;
} }
private static void OnAcceptConnection(IAsyncResult asyn)
public static void Stop()
{
if (SetAsSystemProxy)
{ {
SystemProxyHelper.DisableAllProxy();
FireFoxHelper.RemoveFirefox();
}
ShouldListen = false;
listener.Stop();
listenerThread.Interrupt();
}
private static void Listen(Object obj)
{
TcpListener listener = (TcpListener)obj;
try try
{ {
while (ShouldListen) // Get the listener that handles the client request.
{ _listener.BeginAcceptTcpClient(OnAcceptConnection, _listener);
var client = listener.AcceptTcpClient(); var client = _listener.EndAcceptTcpClient(asyn);
Task.Factory.StartNew(() => HandleClient(client)); var Task = HandleClient(client);
}
} }
catch (ThreadInterruptedException) { } catch
catch (SocketException)
{ {
// ignored
} }
} }
public static void Stop()
{
if (SetAsSystemProxy)
{
SystemProxyHelper.DisableAllProxy();
FireFoxHelper.RemoveFirefox();
}
_listener.Stop();
CertManager.Dispose();
}
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Globalization;
using System.Text;
using System.Threading;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Security.Authentication;
using System.Net.Sockets; using System.Net.Sockets;
using System.Diagnostics; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Text;
using System.Reflection; using System.Text.RegularExpressions;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Http;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer partial class ProxyServer
{ {
private static async Task HandleClient(TcpClient client)
private static void HandleClient(TcpClient Client)
{ {
Stream clientStream = client.GetStream();
var clientStreamWriter = new StreamWriter(clientStream);
string connectionGroup = null; Uri httpRemoteUri;
Stream clientStream = null;
CustomBinaryReader clientStreamReader = null;
StreamWriter connectStreamWriter = null;
string tunnelHostName = null;
int tunnelPort = 0;
try try
{ {
connectionGroup = Dns.GetHostEntry(((IPEndPoint)Client.Client.RemoteEndPoint).Address).HostName;
clientStream = Client.GetStream();
clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
string securehost = null;
List<string> requestLines = new List<string>();
string tmpLine;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
//read the first line HTTP command //read the first line HTTP command
String httpCmd = requestLines.Count > 0 ? requestLines[0] : null; var httpCmd = await HttpStreamReader.ReadLine(clientStream);
if (String.IsNullOrEmpty(httpCmd))
if (string.IsNullOrEmpty(httpCmd))
{ {
throw new EndOfStreamException(); throw new EndOfStreamException();
} }
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0]; //break up the line into three components (method, remote URL & Http Version)
String remoteUri = splitBuffer[1]; var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);
Version version;
string RequestVersion;
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
RequestVersion = "HTTP/1.1";
}
else
{
version = new Version(1, 0);
RequestVersion = "HTTP/1.0";
}
if (splitBuffer[0].ToUpper() == "CONNECT") var httpVerb = httpCmdSplit[0];
{
//Browser wants to create a secure tunnel
//instead = we are going to perform a man in the middle "attack"
//the user's browser should warn them of the certification errors,
//so we need to install our root certficate in users machine as Certificate Authority.
remoteUri = "https://" + splitBuffer[1];
tunnelHostName = splitBuffer[1].Split(':')[0];
int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort);
if (tunnelPort == 0) tunnelPort = 80;
var isSecure = true;
for (int i = 1; i < requestLines.Count; i++)
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "host")) if (httpVerb.ToUpper() == "CONNECT")
{ httpRemoteUri = new Uri("http://" + httpCmdSplit[1]);
var hostDetails = header[1].ToLower().Trim().Split(':'); else
if (hostDetails.Length > 1) httpRemoteUri = new Uri(httpCmdSplit[1]);
{
isSecure = false;
}
}
}
requestLines.Clear();
connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine(RequestVersion + " 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine(String.Format("connection:close"));
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
var httpVersion = httpCmdSplit[2];
var excluded = ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x));
if (tunnelPort != 443) //Client wants to create a secure tcp tunnel (its a HTTPS request)
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port == 443)
{ {
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
await HttpStreamReader.ReadAllLines(clientStream);
WriteConnectResponse(clientStreamWriter, httpVersion);
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); var certificate = CertManager.CreateCertificate(httpRemoteUri.Host);
if (clientStream != null)
clientStream.Close();
return;
}
Monitor.Enter(certificateAccessLock);
var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName);
Monitor.Exit(certificateAccessLock);
SslStream sslStream = null; SslStream sslStream = null;
if (!pinnedCertificateClients.Contains(tunnelHostName) && isSecure)
{
sslStream = new SslStream(clientStream, true);
try
{
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
}
catch (AuthenticationException ex)
{
if (pinnedCertificateClients.Contains(tunnelHostName) == false)
{
pinnedCertificateClients.Add(tunnelHostName);
}
throw ex;
}
} try
else
{ {
sslStream = new SslStream(clientStream, true);
//Successfully managed to authenticate the client using the fake certificate
sslStream.AuthenticateAsServer(certificate, false,
SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); clientStreamWriter = new StreamWriter(sslStream);
if (clientStream != null)
clientStream.Close();
return;
}
clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII);
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream; clientStream = sslStream;
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
} }
//read the new http command. catch
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
if (String.IsNullOrEmpty(httpCmd))
{ {
throw new EndOfStreamException(); if (sslStream != null)
} sslStream.Dispose();
securehost = remoteUri; throw;
} }
HandleHttpSessionRequest(Client, httpCmd, connectionGroup, clientStream, tunnelHostName, requestLines, clientStreamReader, securehost);
httpCmd = await HttpStreamReader.ReadLine(clientStream);
} }
catch (AuthenticationException) else if (httpVerb.ToUpper() == "CONNECT")
{ {
await HttpStreamReader.ReadAllLines(clientStream);
WriteConnectResponse(clientStreamWriter, httpVersion);
TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false);
Dispose(client, clientStream, null, clientStreamWriter, null);
return; return;
} }
catch (EndOfStreamException)
{ //Now create the request
return; HandleHttpSessionRequest(client, httpCmd, clientStream, null, clientStreamWriter,
} httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null);
catch (IOException)
{
return;
}
catch (UriFormatException)
{
return;
} }
catch (WebException) catch
{ {
return; Dispose(client, clientStream, null, clientStreamWriter, null);
} }
finally
{
} }
} private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, string connectionGroup, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, string securehost) string clientStreamReader, StreamWriter clientStreamWriter, string secureTunnelHostName)
{ {
if (string.IsNullOrEmpty(httpCmd))
{
Dispose(client, clientStream, null, clientStreamWriter, null);
return;
}
var args = new SessionEventArgs(BUFFER_SIZE);
if (httpCmd == null) return; args.Client = client;
var args = new SessionEventArgs(BUFFER_SIZE);
args.Client = Client;
args.tunnelHostName = tunnelHostName;
args.securehost = securehost;
try try
{ {
var splitBuffer = httpCmd.Split(spaceSplit, 3); //break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(SpaceSplit, 3);
if (splitBuffer.Length != 3) var httpMethod = httpCmdSplit[0];
{ var httpRemoteUri =
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); new Uri(secureTunnelHostName == null ? httpCmdSplit[1] : (secureTunnelHostName + httpCmdSplit[1]));
var httpVersion = httpCmdSplit[2];
if (clientStream != null)
clientStream.Close();
return;
}
var method = splitBuffer[0];
var remoteUri = splitBuffer[1];
Version version; Version version;
if (splitBuffer[2] == "HTTP/1.1") if (httpVersion == "HTTP/1.1")
{ {
version = new Version(1, 1); version = new Version(1, 1);
} }
...@@ -243,239 +140,218 @@ namespace Titanium.Web.Proxy ...@@ -243,239 +140,218 @@ namespace Titanium.Web.Proxy
version = new Version(1, 0); version = new Version(1, 0);
} }
if (securehost != null) if (httpRemoteUri.Scheme == Uri.UriSchemeHttps)
{ {
remoteUri = securehost + remoteUri; args.IsHttps = true;
args.IsSSLRequest = true;
} }
//construct the web request that we are going to issue on behalf of the client. args.RequestHeaders = new List<HttpHeader>();
args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim());
args.ProxyRequest.Proxy = null;
args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = method;
args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
args.ClientStreamReader = clientStreamReader;
for (int i = 1; i < requestLines.Count; i++) string tmpLine;
{
var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "upgrade") && (header[1] == "websocket")) while (!string.IsNullOrEmpty(tmpLine = await HttpStreamReader.ReadLine(clientStream)))
{ {
var header = tmpLine.Split(ColonSpaceSplit, 2, StringSplitOptions.None);
args.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null)
clientStream.Close();
return;
} }
}
ReadRequestHeaders(ref requestLines, args.ProxyRequest);
int contentLen = (int)args.ProxyRequest.ContentLength;
args.ProxyRequest.AllowAutoRedirect = false;
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
if (BeforeRequest != null) for (var i = 0; i < args.RequestHeaders.Count; i++)
{ {
args.RequestHostname = args.ProxyRequest.RequestUri.Host; var rawHeader = args.RequestHeaders[i];
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.RequestLength = contentLen;
args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)Client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
BeforeRequest(null, args); //if request was upgrade to web-socket protocol then relay the request without proxying
} if ((rawHeader.Name.ToLower() == "upgrade") && (rawHeader.Value.ToLower() == "websocket"))
string tmpLine;
if (args.CancelRequest)
{
if (args.RequestIsAlive)
{ {
requestLines.Clear(); TcpHelper.SendRaw(clientStream, httpCmd, args.RequestHeaders,
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) httpRemoteUri.Host, httpRemoteUri.Port, httpRemoteUri.Scheme == Uri.UriSchemeHttps);
{ Dispose(client, clientStream, null, clientStreamWriter, args);
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
return; return;
} }
else
return;
} }
args.ProxyRequest.ConnectionGroupName = connectionGroup;
args.ProxyRequest.AllowWriteStreamBuffering = true;
//construct the web request that we are going to issue on behalf of the client.
args.ProxyRequest = new HttpClient();
//args.ProxyRequest.Proxy = null;
//args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = httpMethod;
//args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
//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.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.ProxyRequest.AllowWriteStreamBuffering = true;
if (args.RequestWasModified)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] requestBytes = encoding.GetBytes(args.RequestHtmlBody);
args.ProxyRequest.ContentLength = requestBytes.Length;
Stream newStream = args.ProxyRequest.GetRequestStream();
newStream.Write(requestBytes, 0, requestBytes.Length);
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} //If requested interception
else if (BeforeRequest != null)
{
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
{
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args);
}
else
{ {
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); //args.RequestEncoding = args.ProxyRequest.GetEncoding();
} //BeforeRequest(null, args);
} }
args.RequestLocked = true;
if (args.CancelRequest)
}
catch (IOException ex)
{
return;
}
catch (UriFormatException ex)
{
return;
}
catch (WebException ex)
{ {
Dispose(client, clientStream, null, clientStreamWriter, args);
return; return;
} }
finally
{
SetRequestHeaders(args.RequestHeaders, args.ProxyRequest);
//If request was modified by user
if (args.RequestBodyRead)
}
}
private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest)
{ {
args.ProxyRequest.ContentLength = args.RequestBody.Length;
var newStream = await args.ProxyRequest.GetStream();
newStream.Write(args.RequestBody, 0, args.RequestBody.Length);
args.ProxyRequest.BeginGetResponse(HandleHttpSessionResponse, args);
for (int i = 1; i < RequestLines.Count; i++)
{
String httpCmd = RequestLines[i];
String[] header = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None);
if (!String.IsNullOrEmpty(header[0].Trim()))
switch (header[0].ToLower())
{
case "accept":
WebRequest.Accept = header[1];
break;
case "accept-encoding":
WebRequest.Headers.Add(header[0], "gzip,deflate,zlib");
break;
case "cookie":
WebRequest.Headers["Cookie"] = header[1];
break;
case "connection":
if (header[1].ToLower() == "keep-alive")
WebRequest.KeepAlive = true;
break;
case "content-length":
int contentLen;
int.TryParse(header[1], out contentLen);
if (contentLen != 0)
WebRequest.ContentLength = contentLen;
break;
case "content-type":
WebRequest.ContentType = header[1];
break;
case "expect":
if (header[1].ToLower() == "100-continue")
WebRequest.ServicePoint.Expect100Continue = true;
else
WebRequest.Expect = header[1];
break;
case "host":
WebRequest.Host = header[1];
break;
case "if-modified-since":
String[] sb = header[1].Trim().Split(semiSplit);
DateTime d;
if (DateTime.TryParse(sb[0], out d))
WebRequest.IfModifiedSince = d;
break;
case "proxy-connection":
break;
case "range":
var startEnd = header[1].Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) WebRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else WebRequest.AddRange(int.Parse(startEnd[0])); }
else
WebRequest.AddRange(int.Parse(startEnd[0]));
break;
case "referer":
WebRequest.Referer = header[1];
break;
case "user-agent":
WebRequest.UserAgent = header[1];
break;
case "transfer-encoding":
if (header[1].ToLower() == "chunked")
WebRequest.SendChunked = true;
else
WebRequest.SendChunked = false;
break;
case "upgrade":
if (header[1].ToLower() == "http/1.1")
WebRequest.Headers.Add(header[0], header[1]);
break;
default:
if (header.Length >= 2)
WebRequest.Headers.Add(header[0], header[1]);
else
WebRequest.Headers.Add(header[0], "");
break;
} }
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);
}
private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult) //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);
}
catch
{
Dispose(client, clientStream, null, clientStreamWriter, args);
}
}
private static void WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion)
{
clientStreamWriter.WriteLine(httpVersion + " 200 Connection established");
clientStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
clientStreamWriter.WriteLine("connection:close");
clientStreamWriter.WriteLine();
clientStreamWriter.Flush();
}
private static void SetRequestHeaders(List<HttpHeader> requestHeaders, HttpClient webRequest)
{
for (var i = 0; i < requestHeaders.Count; i++)
{
//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")
// webRequest.ServicePoint.Expect100Continue = true;
// else
// webRequest.Expect = requestHeaders[i].Value;
// break;
// case "host":
// webRequest.Host = 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":
// var startEnd = requestHeaders[i].Value.Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
// if (startEnd.Length > 1)
// {
// if (!string.IsNullOrEmpty(startEnd[1]))
// webRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1]));
// else webRequest.AddRange(int.Parse(startEnd[0]));
// }
// else
// webRequest.AddRange(int.Parse(startEnd[0]));
// break;
// case "referer":
// webRequest.Referer = requestHeaders[i].Value;
// break;
// case "user-agent":
// webRequest.UserAgent = requestHeaders[i].Value;
// 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":
// if (requestHeaders[i].Value.ToLower() == "http/1.1")
// webRequest.Headers.Add("Upgrade", requestHeaders[i].Value);
// break;
// default:
// webRequest.Headers.Add(requestHeaders[i].Name, requestHeaders[i].Value);
// break;
//}
requestHeaders.Add(new HttpHeader(requestHeaders[i].Name, requestHeaders[i].Value));
}
}
//This is called when the request is PUT/POST to read the body
private static async Task SendClientRequestBody(SessionEventArgs args)
{ {
var args = (SessionEventArgs)AsynchronousResult.AsyncState;
// End the operation // End the operation
Stream postStream = args.ProxyRequest.EndGetRequestStream(AsynchronousResult); var postStream = args.ProxyRequest.Stream;
if (args.ProxyRequest.ContentLength > 0) if (args.ProxyRequest.ContentLength > 0)
{ {
args.ProxyRequest.AllowWriteStreamBuffering = true; //args.ProxyRequest.AllowWriteStreamBuffering = true;
try try
{ {
var totalbytesRead = 0;
int totalbytesRead = 0;
int bytesToRead; int bytesToRead;
if (args.ProxyRequest.ContentLength < BUFFER_SIZE) if (args.ProxyRequest.ContentLength < BUFFER_SIZE)
...@@ -488,124 +364,65 @@ namespace Titanium.Web.Proxy ...@@ -488,124 +364,65 @@ namespace Titanium.Web.Proxy
while (totalbytesRead < (int)args.ProxyRequest.ContentLength) while (totalbytesRead < (int)args.ProxyRequest.ContentLength)
{ {
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead); var buffer = new byte[bytesToRead];
args.ClientStream.Read(buffer, 0, bytesToRead);
totalbytesRead += buffer.Length; totalbytesRead += buffer.Length;
int RemainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead; var remainingBytes = (int)args.ProxyRequest.ContentLength - totalbytesRead;
if (RemainingBytes < bytesToRead) if (remainingBytes < bytesToRead)
{ {
bytesToRead = RemainingBytes; bytesToRead = remainingBytes;
} }
postStream.Write(buffer, 0, buffer.Length); postStream.Write(buffer, 0, buffer.Length);
} }
postStream.Close(); postStream.Close();
} }
catch (IOException ex) catch
{ {
postStream.Close();
postStream.Dispose();
args.ProxyRequest.KeepAlive = false; throw;
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{
args.ProxyRequest.KeepAlive = false;
Debug.WriteLine(ex.Message);
return;
} }
} }
//Need to revist, find any potential bugs
else if (args.ProxyRequest.SendChunked) else if (args.ProxyRequest.SendChunked)
{ {
args.ProxyRequest.AllowWriteStreamBuffering = true; // args.ProxyRequest.AllowWriteStreamBuffering = true;
try try
{ {
StringBuilder sb = new StringBuilder();
byte[] byteRead = new byte[1];
while (true) while (true)
{ {
var chuchkHead = await HttpStreamReader.ReadLine(args.ClientStream);
var chunkSize = int.Parse(chuchkHead, NumberStyles.HexNumber);
args.ClientStream.Read(byteRead, 0, 1); if (chunkSize != 0)
sb.Append(Encoding.ASCII.GetString(byteRead));
if (sb.ToString().EndsWith(Environment.NewLine))
{
var chunkSizeInHex = sb.ToString().Replace(Environment.NewLine, String.Empty);
var chunckSize = int.Parse(chunkSizeInHex, System.Globalization.NumberStyles.HexNumber);
if (chunckSize == 0)
{
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
break;
}
var totalbytesRead = 0;
int bytesToRead;
if (chunckSize < BUFFER_SIZE)
{ {
bytesToRead = chunckSize; var buffer = new byte[chunkSize];
args.ClientStream.Read(buffer,0,chunkSize);
postStream.Write(buffer, 0, buffer.Length);
//chunk trail
await HttpStreamReader.ReadLine(args.ClientStream);
} }
else else
bytesToRead = BUFFER_SIZE;
while (totalbytesRead < chunckSize)
{ {
var buffer = args.ClientStreamReader.ReadBytes(bytesToRead); await HttpStreamReader.ReadLine(args.ClientStream);
totalbytesRead += buffer.Length; break;
int RemainingBytes = chunckSize - totalbytesRead;
if (RemainingBytes < bytesToRead)
{
bytesToRead = RemainingBytes;
} }
postStream.Write(buffer, 0, buffer.Length);
} }
for (int i = 0; i < Encoding.ASCII.GetByteCount(Environment.NewLine); i++)
{
args.ClientStream.ReadByte();
}
sb.Clear();
}
}
postStream.Close(); postStream.Close();
} }
catch (IOException ex) catch
{
if (postStream != null)
postStream.Close();
args.ProxyRequest.KeepAlive = false;
Debug.WriteLine(ex.Message);
return;
}
catch (WebException ex)
{ {
if (postStream != null)
postStream.Close(); postStream.Close();
postStream.Dispose();
args.ProxyRequest.KeepAlive = false; throw;
Debug.WriteLine(ex.Message);
return;
} }
} }
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Security; using System.Net.Sockets;
using System.Threading; using System.Text;
using System.Security.Authentication;
using System.Diagnostics;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Helpers;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Http;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer partial class ProxyServer
{ {
private static void HandleHttpSessionResponse(IAsyncResult AsynchronousResult) //Called asynchronously when a request was successfully and we received the response
private static async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
SessionEventArgs args = (SessionEventArgs)AsynchronousResult.AsyncState; await args.ProxyRequest.ReceiveResponse();
try
{
args.ServerResponse = (HttpWebResponse)args.ProxyRequest.EndGetResponse(AsynchronousResult);
}
catch (WebException webEx)
{
args.ProxyRequest.KeepAlive = false;
args.ServerResponse = webEx.Response as HttpWebResponse;
}
Stream serverResponseStream = null;
Stream clientWriteStream = args.ClientStream;
StreamWriter responseWriter = null;
try try
{ {
if (args.ProxyRequest != null)
responseWriter = new StreamWriter(clientWriteStream);
if (args.ServerResponse != null)
{ {
List<Tuple<String, String>> responseHeaders = ProcessResponse(args.ServerResponse); args.ResponseHeaders = ReadResponseHeaders(args.ProxyRequest);
args.ResponseStream = args.ProxyRequest.GetResponseStream();
serverResponseStream = args.ServerResponse.GetResponseStream();
args.ServerResponseStream = serverResponseStream;
if (args.ServerResponse.Headers.Count == 0 && args.ServerResponse.ContentLength == -1)
args.ProxyRequest.KeepAlive = false;
bool isChunked = args.ServerResponse.GetResponseHeader("transfer-encoding") == null ? false : args.ServerResponse.GetResponseHeader("transfer-encoding").ToLower() == "chunked" ? true : false;
args.ProxyRequest.KeepAlive = args.ServerResponse.GetResponseHeader("connection") == null ? args.ProxyRequest.KeepAlive : (args.ServerResponse.GetResponseHeader("connection") == "close" ? false : args.ProxyRequest.KeepAlive);
args.UpgradeProtocol = args.ServerResponse.GetResponseHeader("upgrade") == null ? null : args.ServerResponse.GetResponseHeader("upgrade");
if (BeforeResponse != null) if (BeforeResponse != null)
{
args.ResponseEncoding = args.ProxyRequest.GetEncoding();
BeforeResponse(null, args); BeforeResponse(null, args);
}
args.ResponseLocked = true;
if (args.ResponseWasModified) if (args.ResponseBodyRead)
{ {
var isChunked = args.ProxyRequest.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked");
var contentEncoding = args.ProxyRequest.ContentEncoding;
byte[] data; switch (contentEncoding.ToLower())
switch (args.ServerResponse.ContentEncoding)
{ {
case "gzip": case "gzip":
data = CompressionHelper.CompressGzip(args.ResponseHtmlBody, args.Encoding); args.ResponseBody = CompressionHelper.CompressGzip(args.ResponseBody);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break; break;
case "deflate": case "deflate":
data = CompressionHelper.CompressDeflate(args.ResponseHtmlBody, args.Encoding); args.ResponseBody = CompressionHelper.CompressDeflate(args.ResponseBody);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break; break;
case "zlib": case "zlib":
data = CompressionHelper.CompressZlib(args.ResponseHtmlBody, args.Encoding); args.ResponseBody = CompressionHelper.CompressZlib(args.ResponseBody);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break; break;
default:
data = EncodeData(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked);
break;
}
} }
else
{
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter);
WriteResponseHeaders(responseWriter, responseHeaders);
if (isChunked)
SendChunked(serverResponseStream, clientWriteStream);
else
SendNormal(serverResponseStream, clientWriteStream);
}
clientWriteStream.Flush();
WriteResponseStatus(args.ProxyRequest.ProtocolVersion, args.ProxyRequest.StatusCode,
args.ProxyRequest.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders, args.ResponseBody.Length,
isChunked);
WriteResponseBody(args.ClientStream, args.ResponseBody, isChunked);
} }
else else
args.ProxyRequest.KeepAlive = false;
}
catch (IOException ex)
{ {
var isChunked = args.ProxyRequest.GetResponseHeader("transfer-encoding").ToLower().Contains("chunked");
args.ProxyRequest.KeepAlive = false; WriteResponseStatus(args.ProxyRequest.ProtocolVersion, args.ProxyRequest.StatusCode,
Debug.WriteLine(ex.Message); args.ProxyRequest.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(args.ClientStreamWriter, args.ResponseHeaders);
WriteResponseBody(args.ResponseStream, args.ClientStream, isChunked);
} }
catch (SocketException ex)
{
args.ProxyRequest.KeepAlive = false;
Debug.WriteLine(ex.Message);
args.ClientStream.Flush();
} }
catch (ArgumentException ex)
{
args.ProxyRequest.KeepAlive = false;
Debug.WriteLine(ex.Message);
} }
catch (WebException ex) catch
{ {
args.ProxyRequest.KeepAlive = false; Dispose(args.Client, args.ClientStream, null, args.ClientStreamWriter, args);
Debug.WriteLine(ex.Message);
} }
finally finally
{ {
args.Dispose();
if (args.ProxyRequest != null) args.ProxyRequest.Abort(); }
if (args.ServerResponseStream != null) args.ServerResponseStream.Close();
if (args.ServerResponse != null)
args.ServerResponse.Close();
} }
if (args.ProxyRequest.KeepAlive == false) private static List<HttpHeader> ReadResponseHeaders(HttpWebResponse response)
{ {
if (responseWriter != null) var returnHeaders = new List<HttpHeader>();
responseWriter.Close();
if (clientWriteStream != null)
clientWriteStream.Close();
args.Client.Close(); string cookieHeaderName = null;
} string cookieHeaderValue = null;
else
{
string httpCmd, tmpLine;
List<string> requestLines = new List<string>();
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = args.ClientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
TcpClient Client = args.Client;
HandleHttpSessionRequest(Client, httpCmd, args.ProxyRequest.ConnectionGroupName, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost);
}
} foreach (string headerKey in response.Headers.Keys)
private static List<Tuple<String, String>> ProcessResponse(HttpWebResponse Response)
{
String value = null;
String header = null;
List<Tuple<String, String>> returnHeaders = new List<Tuple<String, String>>();
foreach (String s in Response.Headers.Keys)
{ {
if (s.ToLower() == "set-cookie") if (headerKey.ToLower() == "set-cookie")
{ {
header = s; cookieHeaderName = headerKey;
value = Response.Headers[s]; cookieHeaderValue = response.Headers[headerKey];
} }
else else
returnHeaders.Add(new Tuple<String, String>(s, Response.Headers[s])); returnHeaders.Add(new HttpHeader(headerKey, response.Headers[headerKey]));
} }
if (!String.IsNullOrWhiteSpace(value)) if (!string.IsNullOrWhiteSpace(cookieHeaderValue))
{ {
Response.Headers.Remove(header); response.Headers.Remove(cookieHeaderName);
String[] cookies = cookieSplitRegEx.Split(value); var cookies = CookieSplitRegEx.Split(cookieHeaderValue);
foreach (String cookie in cookies) foreach (var cookie in cookies)
returnHeaders.Add(new Tuple<String, String>("Set-Cookie", cookie)); returnHeaders.Add(new HttpHeader("Set-Cookie", cookie));
} }
return returnHeaders; return returnHeaders;
} }
private static void WriteResponseStatus(Version Version, HttpStatusCode Code, String Description, StreamWriter ResponseWriter) private static void WriteResponseStatus(Version version, HttpStatusCode code, string description,
StreamWriter responseWriter)
{ {
String s = String.Format("HTTP/{0}.{1} {2} {3}", Version.Major, Version.Minor, (Int32)Code, Description); var s = string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, (int)code, description);
ResponseWriter.WriteLine(s); responseWriter.WriteLine(s);
} }
private static void WriteResponseHeaders(StreamWriter ResponseWriter, List<Tuple<String, String>> Headers) private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
{ {
if (Headers != null) if (headers != null)
{ {
foreach (Tuple<String, String> header in Headers) foreach (var header in headers)
{ {
responseWriter.WriteLine(header.ToString());
ResponseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2));
} }
} }
ResponseWriter.WriteLine(); responseWriter.WriteLine();
ResponseWriter.Flush(); responseWriter.Flush();
} }
private static void WriteResponseHeaders(StreamWriter ResponseWriter, List<Tuple<String, String>> Headers, int Length)
private static void WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers, int length,
bool isChunked)
{ {
if (Headers != null) if (!isChunked)
{ {
if (headers.Any(x => x.Name.ToLower() == "content-length") == false)
foreach (Tuple<String, String> header in Headers)
{ {
if (header.Item1.ToLower() != "content-length") headers.Add(new HttpHeader("Content-Length", length.ToString()));
ResponseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2));
else
ResponseWriter.WriteLine(String.Format("{0}: {1}", "content-length", Length.ToString()));
} }
} }
ResponseWriter.WriteLine(); if (headers != null)
ResponseWriter.Flush(); {
foreach (var header in headers)
{
if (!isChunked && header.Name.ToLower() == "content-length")
header.Value = length.ToString();
responseWriter.WriteLine(header.ToString());
}
}
responseWriter.WriteLine();
responseWriter.Flush();
} }
public static void SendNormal(Stream InStream, Stream OutStream)
private static void WriteResponseBody(Stream clientStream, byte[] data, bool isChunked)
{ {
if (!isChunked)
{
clientStream.Write(data, 0, data.Length);
}
else
WriteResponseBodyChunked(data, clientStream);
}
Byte[] buffer = new Byte[BUFFER_SIZE]; private static void WriteResponseBody(Stream inStream, Stream outStream, bool isChunked)
{
if (!isChunked)
{
var buffer = new byte[BUFFER_SIZE];
int bytesRead; int bytesRead;
while ((bytesRead = InStream.Read(buffer, 0, buffer.Length)) > 0) while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0)
{ {
outStream.Write(buffer, 0, bytesRead);
OutStream.Write(buffer, 0, bytesRead);
} }
} }
public static void SendChunked(Stream InStream, Stream OutStream) else
{ WriteResponseBodyChunked(inStream, outStream);
}
Byte[] buffer = new Byte[BUFFER_SIZE];
var ChunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine); //Send chunked response
private static void WriteResponseBodyChunked(Stream inStream, Stream outStream)
{
var buffer = new byte[BUFFER_SIZE];
int bytesRead; int bytesRead;
while ((bytesRead = InStream.Read(buffer, 0, buffer.Length)) > 0) while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0)
{ {
var chunkHead = Encoding.ASCII.GetBytes(bytesRead.ToString("x2"));
var ChunkHead = Encoding.ASCII.GetBytes(bytesRead.ToString("x2")); outStream.Write(chunkHead, 0, chunkHead.Length);
OutStream.Write(ChunkHead, 0, ChunkHead.Length); outStream.Write(ChunkTrail, 0, ChunkTrail.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length); outStream.Write(buffer, 0, bytesRead);
OutStream.Write(buffer, 0, bytesRead); outStream.Write(ChunkTrail, 0, ChunkTrail.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length);
} }
var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
OutStream.Write(ChunkEnd, 0, ChunkEnd.Length); outStream.Write(ChunkEnd, 0, ChunkEnd.Length);
} }
public static void SendChunked(byte[] Data, Stream OutStream)
{
Byte[] buffer = new Byte[BUFFER_SIZE];
var ChunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine);
var ChunkHead = Encoding.ASCII.GetBytes(Data.Length.ToString("x2"));
OutStream.Write(ChunkHead, 0, ChunkHead.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length);
OutStream.Write(Data, 0, Data.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length);
private static void WriteResponseBodyChunked(byte[] data, Stream outStream)
{
var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine); outStream.Write(chunkHead, 0, chunkHead.Length);
outStream.Write(ChunkTrail, 0, ChunkTrail.Length);
outStream.Write(data, 0, data.Length);
outStream.Write(ChunkTrail, 0, ChunkTrail.Length);
OutStream.Write(ChunkEnd, 0, ChunkEnd.Length); outStream.Write(ChunkEnd, 0, ChunkEnd.Length);
} }
public static byte[] EncodeData(string ResponseData, Encoding e) private static void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader,
IDisposable clientStreamWriter, IDisposable args)
{ {
if (args != null)
args.Dispose();
return e.GetBytes(ResponseData); if (clientStreamReader != null)
clientStreamReader.Dispose();
if (clientStreamWriter != null)
clientStreamWriter.Dispose();
} if (clientStream != null)
clientStream.Dispose();
public static void SendData(Stream OutStream, byte[] Data, bool IsChunked) if (client != null)
{ client.Close();
if (!IsChunked)
{
OutStream.Write(Data, 0, Data.Length);
} }
else
SendChunked(Data, OutStream);
}
} }
} }
\ No newline at end of file
...@@ -66,9 +66,29 @@ ...@@ -66,9 +66,29 @@
<Reference Include="Ionic.Zip"> <Reference Include="Ionic.Zip">
<HintPath>..\packages\DotNetZip.1.9.3\lib\net20\Ionic.Zip.dll</HintPath> <HintPath>..\packages\DotNetZip.1.9.3\lib\net20\Ionic.Zip.dll</HintPath>
</Reference> </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>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.configuration" /> <Reference Include="System.configuration" />
<Reference Include="System.Core" /> <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.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
...@@ -76,23 +96,30 @@ ...@@ -76,23 +96,30 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Helpers\CertificateManager.cs" /> <Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" /> <Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" /> <Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RequestHandler.cs" /> <Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" /> <Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" />
<Compile Include="Helpers\NetFramework.cs" /> <Compile Include="Helpers\NetFramework.cs" />
<Compile Include="Helpers\Compression.cs" /> <Compile Include="Helpers\Compression.cs" />
<Compile Include="ProxyServer.cs" /> <Compile Include="ProxyServer.cs" />
<Compile Include="Models\SessionEventArgs.cs" /> <Compile Include="EventArguments\SessionEventArgs.cs" />
<Compile Include="Helpers\Tcp.cs" /> <Compile Include="Helpers\Tcp.cs" />
<Compile Include="Helpers\Stream.cs" /> <Compile Include="Extensions\StreamExtensions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Properties\" /> <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> <ItemGroup>
<None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="Titanium_Proxy_Test_Root.cer"> <None Include="Titanium_Proxy_Test_Root.cer">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
...@@ -111,6 +138,11 @@ ...@@ -111,6 +138,11 @@
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" /> <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target> </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. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">
......
<?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"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="DotNetZip" version="1.9.3" targetFramework="net40-Client" /> <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" />
</packages> </packages>
\ 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