Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
5e1841ff
Unverified
Commit
5e1841ff
authored
Mar 25, 2018
by
honfika
Committed by
GitHub
Mar 25, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #390 from justcoding121/develop
merge to beta (again)
parents
b27ba8cf
fa0d9f2a
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
749 additions
and
644 deletions
+749
-644
ProxyTestController.cs
.../Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
+43
-15
MainWindow.xaml.cs
Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
+31
-6
SessionListItem.cs
Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs
+7
-0
Titanium.Web.Proxy.Examples.Wpf.csproj
...Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj
+2
-2
packages.config
Examples/Titanium.Web.Proxy.Examples.Wpf/packages.config
+1
-1
Titanium.Web.Proxy.UnitTests.csproj
...m.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
+2
-1
CompressionFactory.cs
Titanium.Web.Proxy/Compression/CompressionFactory.cs
+7
-6
DeflateCompression.cs
Titanium.Web.Proxy/Compression/DeflateCompression.cs
+2
-10
GZipCompression.cs
Titanium.Web.Proxy/Compression/GZipCompression.cs
+2
-10
ICompression.cs
Titanium.Web.Proxy/Compression/ICompression.cs
+3
-2
DecompressionFactory.cs
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
+14
-7
DefaultDecompression.cs
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
+0
-15
DeflateDecompression.cs
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
+2
-23
GZipDecompression.cs
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
+2
-22
IDecompression.cs
Titanium.Web.Proxy/Decompression/IDecompression.cs
+3
-2
LimitedStream.cs
Titanium.Web.Proxy/EventArguments/LimitedStream.cs
+139
-0
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+75
-45
TransformationMode.cs
Titanium.Web.Proxy/EventArguments/TransformationMode.cs
+23
-0
HttpWriter.cs
Titanium.Web.Proxy/Helpers/HttpWriter.cs
+22
-17
SystemProxy.cs
Titanium.Web.Proxy/Helpers/SystemProxy.cs
+1
-1
ConnectResponse.cs
Titanium.Web.Proxy/Http/ConnectResponse.cs
+0
-1
KnownHeaders.cs
Titanium.Web.Proxy/Http/KnownHeaders.cs
+2
-3
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+5
-162
RequestResponseBase.cs
Titanium.Web.Proxy/Http/RequestResponseBase.cs
+178
-0
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+4
-156
BCCertificateMaker.cs
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
+1
-1
WinCertificateMaker.cs
...nium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
+1
-1
ProxyServer.cs
Titanium.Web.Proxy/ProxyServer.cs
+5
-0
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+138
-120
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+31
-12
Titanium.Web.Proxy.csproj
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
+1
-1
Titanium.Web.Proxy.nuspec
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
+1
-1
packages.config
Titanium.Web.Proxy/packages.config
+1
-1
No files found.
Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
View file @
5e1841ff
...
@@ -5,6 +5,7 @@ using System.Net;
...
@@ -5,6 +5,7 @@ using System.Net;
using
System.Net.Security
;
using
System.Net.Security
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -13,6 +14,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -13,6 +14,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
{
public
class
ProxyTestController
public
class
ProxyTestController
{
{
private
readonly
object
lockObj
=
new
object
();
private
readonly
ProxyServer
proxyServer
;
private
readonly
ProxyServer
proxyServer
;
private
ExplicitProxyEndPoint
explicitEndPoint
;
private
ExplicitProxyEndPoint
explicitEndPoint
;
...
@@ -33,11 +36,28 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -33,11 +36,28 @@ namespace Titanium.Web.Proxy.Examples.Basic
//generate root certificate without storing it in file system
//generate root certificate without storing it in file system
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.CreateRootCertificate(false);
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificate();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
//proxyServer.CertificateManager.TrustRootCertificateAsAdmin();
proxyServer
.
ExceptionFunc
=
exception
=>
Console
.
WriteLine
(
exception
.
Message
);
proxyServer
.
ExceptionFunc
=
exception
=>
{
lock
(
lockObj
)
{
var
color
=
Console
.
ForegroundColor
;
Console
.
ForegroundColor
=
ConsoleColor
.
Red
;
if
(
exception
is
ProxyHttpException
phex
)
{
Console
.
WriteLine
(
exception
.
Message
+
": "
+
phex
.
InnerException
?.
Message
);
}
else
{
Console
.
WriteLine
(
exception
.
Message
);
}
Console
.
ForegroundColor
=
color
;
}
};
proxyServer
.
ForwardToUpstreamGateway
=
true
;
proxyServer
.
ForwardToUpstreamGateway
=
true
;
proxyServer
.
CertificateManager
.
SaveFakeCertificates
=
true
;
proxyServer
.
CertificateManager
.
SaveFakeCertificates
=
true
;
//optionally set the Certificate Engine
//optionally set the Certificate Engine
...
@@ -52,7 +72,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -52,7 +72,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
{
proxyServer
.
BeforeRequest
+=
OnRequest
;
proxyServer
.
BeforeRequest
+=
OnRequest
;
proxyServer
.
BeforeResponse
+=
OnResponse
;
proxyServer
.
BeforeResponse
+=
OnResponse
;
proxyServer
.
ServerCertificateValidationCallback
+=
OnCertificateValidation
;
proxyServer
.
ServerCertificateValidationCallback
+=
OnCertificateValidation
;
proxyServer
.
ClientCertificateSelectionCallback
+=
OnCertificateSelection
;
proxyServer
.
ClientCertificateSelectionCallback
+=
OnCertificateSelection
;
...
@@ -60,12 +80,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -60,12 +80,12 @@ namespace Titanium.Web.Proxy.Examples.Basic
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
explicitEndPoint
=
new
ExplicitProxyEndPoint
(
IPAddress
.
Any
,
8000
,
true
)
{
{
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Use self-issued generic certificate on all https requests
//Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain
//Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients
//Useful when certificate trust is not required by proxy clients
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
};
};
//Fired when a CONNECT request is received
//Fired when a CONNECT request is received
...
@@ -125,7 +145,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -125,7 +145,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
private
async
Task
OnBeforeTunnelConnectRequest
(
object
sender
,
TunnelConnectSessionEventArgs
e
)
{
{
string
hostname
=
e
.
WebSession
.
Request
.
RequestUri
.
Host
;
string
hostname
=
e
.
WebSession
.
Request
.
RequestUri
.
Host
;
Console
.
WriteLin
e
(
"Tunnel to: "
+
hostname
);
WriteToConsol
e
(
"Tunnel to: "
+
hostname
);
if
(
hostname
.
Contains
(
"dropbox.com"
))
if
(
hostname
.
Contains
(
"dropbox.com"
))
{
{
...
@@ -143,8 +163,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -143,8 +163,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
//intecept & cancel redirect or update requests
//intecept & cancel redirect or update requests
private
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
private
async
Task
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLin
e
(
"Active Client Connections:"
+
((
ProxyServer
)
sender
).
ClientConnectionCount
);
WriteToConsol
e
(
"Active Client Connections:"
+
((
ProxyServer
)
sender
).
ClientConnectionCount
);
Console
.
WriteLin
e
(
e
.
WebSession
.
Request
.
Url
);
WriteToConsol
e
(
e
.
WebSession
.
Request
.
Url
);
//read request headers
//read request headers
requestHeaderHistory
[
e
.
Id
]
=
e
.
WebSession
.
Request
.
Headers
;
requestHeaderHistory
[
e
.
Id
]
=
e
.
WebSession
.
Request
.
Headers
;
...
@@ -192,16 +212,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -192,16 +212,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
private
void
MultipartRequestPartSent
(
object
sender
,
MultipartRequestPartSentEventArgs
e
)
private
void
MultipartRequestPartSent
(
object
sender
,
MultipartRequestPartSentEventArgs
e
)
{
{
var
session
=
(
SessionEventArgs
)
sender
;
var
session
=
(
SessionEventArgs
)
sender
;
Console
.
WriteLin
e
(
"Multipart form data headers:"
);
WriteToConsol
e
(
"Multipart form data headers:"
);
foreach
(
var
header
in
e
.
Headers
)
foreach
(
var
header
in
e
.
Headers
)
{
{
Console
.
WriteLine
(
header
);
WriteToConsole
(
header
.
ToString
()
);
}
}
}
}
private
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
private
async
Task
OnResponse
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLin
e
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
WriteToConsol
e
(
"Active Server Connections:"
+
((
ProxyServer
)
sender
).
ServerConnectionCount
);
//if (requestBodyHistory.ContainsKey(e.Id))
//if (requestBodyHistory.ContainsKey(e.Id))
//{
//{
...
@@ -213,7 +233,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -213,7 +233,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//responseHeaderHistory[e.Id] = e.WebSession.Response.Headers;
//responseHeaderHistory[e.Id] = e.WebSession.Response.Headers;
//// print out process id of current session
//// print out process id of current session
////
Console.WriteLin
e($"PID: {e.WebSession.ProcessId.Value}");
////
WriteToConsol
e($"PID: {e.WebSession.ProcessId.Value}");
////if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
////if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
//if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
//if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")
...
@@ -259,5 +279,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
...
@@ -259,5 +279,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
return
Task
.
FromResult
(
0
);
return
Task
.
FromResult
(
0
);
}
}
private
void
WriteToConsole
(
string
message
)
{
lock
(
lockObj
)
{
Console
.
WriteLine
(
message
);
}
}
}
}
}
}
Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
View file @
5e1841ff
...
@@ -3,6 +3,7 @@ using System.Collections.Generic;
...
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using
System.Collections.ObjectModel
;
using
System.Collections.ObjectModel
;
using
System.Linq
;
using
System.Linq
;
using
System.Net
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
System.Windows
;
using
System.Windows
;
using
System.Windows.Controls
;
using
System.Windows.Controls
;
...
@@ -102,6 +103,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -102,6 +103,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer
.
BeforeRequest
+=
ProxyServer_BeforeRequest
;
proxyServer
.
BeforeRequest
+=
ProxyServer_BeforeRequest
;
proxyServer
.
BeforeResponse
+=
ProxyServer_BeforeResponse
;
proxyServer
.
BeforeResponse
+=
ProxyServer_BeforeResponse
;
proxyServer
.
AfterResponse
+=
ProxyServer_AfterResponse
;
explicitEndPoint
.
BeforeTunnelConnectRequest
+=
ProxyServer_BeforeTunnelConnectRequest
;
explicitEndPoint
.
BeforeTunnelConnectRequest
+=
ProxyServer_BeforeTunnelConnectRequest
;
explicitEndPoint
.
BeforeTunnelConnectResponse
+=
ProxyServer_BeforeTunnelConnectResponse
;
explicitEndPoint
.
BeforeTunnelConnectResponse
+=
ProxyServer_BeforeTunnelConnectResponse
;
proxyServer
.
ClientConnectionCountChanged
+=
delegate
{
Dispatcher
.
Invoke
(()
=>
{
ClientConnectionCount
=
proxyServer
.
ClientConnectionCount
;
});
};
proxyServer
.
ClientConnectionCountChanged
+=
delegate
{
Dispatcher
.
Invoke
(()
=>
{
ClientConnectionCount
=
proxyServer
.
ClientConnectionCount
;
});
};
...
@@ -179,6 +181,17 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -179,6 +181,17 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
}
}
}
private
async
Task
ProxyServer_AfterResponse
(
object
sender
,
SessionEventArgs
e
)
{
await
Dispatcher
.
InvokeAsync
(()
=>
{
if
(
sessionDictionary
.
TryGetValue
(
e
.
WebSession
,
out
var
item
))
{
item
.
Exception
=
e
.
Exception
;
}
});
}
private
SessionListItem
AddSession
(
SessionEventArgs
e
)
private
SessionListItem
AddSession
(
SessionEventArgs
e
)
{
{
var
item
=
CreateSessionListItem
(
e
);
var
item
=
CreateSessionListItem
(
e
);
...
@@ -255,9 +268,12 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -255,9 +268,12 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
}
//string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
//string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxRequest
.
Text
=
request
.
HeaderText
+
request
.
Encoding
.
GetString
(
data
)
+
var
sb
=
new
StringBuilder
();
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
)
+
sb
.
Append
(
request
.
HeaderText
);
(
request
as
ConnectRequest
)?.
ClientHelloInfo
;
sb
.
Append
(
request
.
Encoding
.
GetString
(
data
));
sb
.
Append
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
);
sb
.
Append
((
request
as
ConnectRequest
)?.
ClientHelloInfo
);
TextBoxRequest
.
Text
=
sb
.
ToString
();
var
response
=
session
.
Response
;
var
response
=
session
.
Response
;
data
=
(
response
.
IsBodyRead
?
response
.
Body
:
null
)
??
new
byte
[
0
];
data
=
(
response
.
IsBodyRead
?
response
.
Body
:
null
)
??
new
byte
[
0
];
...
@@ -268,9 +284,18 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -268,9 +284,18 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
}
//hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
//hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxResponse
.
Text
=
session
.
Response
.
HeaderText
+
session
.
Response
.
Encoding
.
GetString
(
data
)
+
sb
=
new
StringBuilder
();
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
)
+
sb
.
Append
(
response
.
HeaderText
);
(
session
.
Response
as
ConnectResponse
)?.
ServerHelloInfo
;
sb
.
Append
(
response
.
Encoding
.
GetString
(
data
));
sb
.
Append
(
truncated
?
Environment
.
NewLine
+
$"Data is truncated after
{
truncateLimit
}
bytes"
:
null
);
sb
.
Append
((
response
as
ConnectResponse
)?.
ServerHelloInfo
);
if
(
SelectedSession
.
Exception
!=
null
)
{
sb
.
Append
(
Environment
.
NewLine
);
sb
.
Append
(
SelectedSession
.
Exception
);
}
TextBoxResponse
.
Text
=
sb
.
ToString
();
}
}
}
}
}
}
Examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs
View file @
5e1841ff
...
@@ -17,6 +17,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -17,6 +17,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private
string
process
;
private
string
process
;
private
long
receivedDataCount
;
private
long
receivedDataCount
;
private
long
sentDataCount
;
private
long
sentDataCount
;
private
Exception
exception
;
public
int
Number
{
get
;
set
;
}
public
int
Number
{
get
;
set
;
}
...
@@ -72,6 +73,12 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -72,6 +73,12 @@ namespace Titanium.Web.Proxy.Examples.Wpf
set
=>
SetField
(
ref
sentDataCount
,
value
);
set
=>
SetField
(
ref
sentDataCount
,
value
);
}
}
public
Exception
Exception
{
get
=>
exception
;
set
=>
SetField
(
ref
exception
,
value
);
}
public
event
PropertyChangedEventHandler
PropertyChanged
;
public
event
PropertyChangedEventHandler
PropertyChanged
;
protected
void
SetField
<
T
>(
ref
T
field
,
T
value
,[
CallerMemberName
]
string
propertyName
=
null
)
protected
void
SetField
<
T
>(
ref
T
field
,
T
value
,[
CallerMemberName
]
string
propertyName
=
null
)
...
...
Examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj
View file @
5e1841ff
...
@@ -51,8 +51,8 @@
...
@@ -51,8 +51,8 @@
<WarningLevel>
4
</WarningLevel>
<WarningLevel>
4
</WarningLevel>
</PropertyGroup>
</PropertyGroup>
<ItemGroup>
<ItemGroup>
<Reference
Include=
"StreamExtended, Version=1.0.1
38
.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"
>
<Reference
Include=
"StreamExtended, Version=1.0.1
41
.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"
>
<HintPath>
..\..\packages\StreamExtended.1.0.1
38
-beta\lib\net45\StreamExtended.dll
</HintPath>
<HintPath>
..\..\packages\StreamExtended.1.0.1
41
-beta\lib\net45\StreamExtended.dll
</HintPath>
</Reference>
</Reference>
<Reference
Include=
"System"
/>
<Reference
Include=
"System"
/>
<Reference
Include=
"System.Data"
/>
<Reference
Include=
"System.Data"
/>
...
...
Examples/Titanium.Web.Proxy.Examples.Wpf/packages.config
View file @
5e1841ff
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
packages
>
<
packages
>
<
package
id
=
"StreamExtended"
version
=
"1.0.1
38
-beta"
targetFramework
=
"net45"
/>
<
package
id
=
"StreamExtended"
version
=
"1.0.1
41
-beta"
targetFramework
=
"net45"
/>
</
packages
>
</
packages
>
\ No newline at end of file
Tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj
View file @
5e1841ff
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
<AppDesignerFolder>
Properties
</AppDesignerFolder>
<AppDesignerFolder>
Properties
</AppDesignerFolder>
<RootNamespace>
Titanium.Web.Proxy.UnitTests
</RootNamespace>
<RootNamespace>
Titanium.Web.Proxy.UnitTests
</RootNamespace>
<AssemblyName>
Titanium.Web.Proxy.UnitTests
</AssemblyName>
<AssemblyName>
Titanium.Web.Proxy.UnitTests
</AssemblyName>
<TargetFrameworkVersion>
v4.5.
1
</TargetFrameworkVersion>
<TargetFrameworkVersion>
v4.5.
2
</TargetFrameworkVersion>
<FileAlignment>
512
</FileAlignment>
<FileAlignment>
512
</FileAlignment>
<ProjectTypeGuids>
{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
</ProjectTypeGuids>
<ProjectTypeGuids>
{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
</ProjectTypeGuids>
<VisualStudioVersion
Condition=
"'$(VisualStudioVersion)' == ''"
>
10.0
</VisualStudioVersion>
<VisualStudioVersion
Condition=
"'$(VisualStudioVersion)' == ''"
>
10.0
</VisualStudioVersion>
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
<ReferencePath>
$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
</ReferencePath>
<ReferencePath>
$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
</ReferencePath>
<IsCodedUITest>
False
</IsCodedUITest>
<IsCodedUITest>
False
</IsCodedUITest>
<TestProjectType>
UnitTest
</TestProjectType>
<TestProjectType>
UnitTest
</TestProjectType>
<TargetFrameworkProfile
/>
</PropertyGroup>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<DebugSymbols>
true
</DebugSymbols>
<DebugSymbols>
true
</DebugSymbols>
...
...
Titanium.Web.Proxy/Compression/CompressionFactory.cs
View file @
5e1841ff
using
System
;
using
System
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy.Compression
namespace
Titanium.Web.Proxy.Compression
{
{
/// <summary>
/// <summary>
/// A factory to generate the compression methods based on the type of compression
/// A factory to generate the compression methods based on the type of compression
/// </summary>
/// </summary>
internal
class
CompressionFactory
internal
static
class
CompressionFactory
{
{
//cache
//cache
private
static
Lazy
<
ICompression
>
gzip
=
new
Lazy
<
ICompression
>(()
=>
new
GZipCompression
());
private
static
readonly
Lazy
<
ICompression
>
gzip
=
new
Lazy
<
ICompression
>(()
=>
new
GZipCompression
());
private
static
Lazy
<
ICompression
>
deflate
=
new
Lazy
<
ICompression
>(()
=>
new
DeflateCompression
());
private
static
readonly
Lazy
<
ICompression
>
deflate
=
new
Lazy
<
ICompression
>(()
=>
new
DeflateCompression
());
public
static
ICompression
GetCompression
(
string
type
)
public
static
ICompression
GetCompression
(
string
type
)
{
{
switch
(
type
)
switch
(
type
)
{
{
case
"gzip"
:
case
KnownHeaders
.
ContentEncodingGzip
:
return
gzip
.
Value
;
return
gzip
.
Value
;
case
"deflate"
:
case
KnownHeaders
.
ContentEncodingDeflate
:
return
deflate
.
Value
;
return
deflate
.
Value
;
default
:
default
:
return
null
;
throw
new
Exception
(
$"Unsupported compression mode:
{
type
}
"
)
;
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Compression/DeflateCompression.cs
View file @
5e1841ff
...
@@ -9,17 +9,9 @@ namespace Titanium.Web.Proxy.Compression
...
@@ -9,17 +9,9 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
/// </summary>
internal
class
DeflateCompression
:
ICompression
internal
class
DeflateCompression
:
ICompression
{
{
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
public
Stream
GetStream
(
Stream
stream
)
{
{
using
(
var
ms
=
new
MemoryStream
())
return
new
DeflateStream
(
stream
,
CompressionMode
.
Compress
,
true
);
{
using
(
var
zip
=
new
DeflateStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
await
zip
.
WriteAsync
(
responseBody
,
0
,
responseBody
.
Length
);
}
return
ms
.
ToArray
();
}
}
}
}
}
}
}
Titanium.Web.Proxy/Compression/GZipCompression.cs
View file @
5e1841ff
...
@@ -9,17 +9,9 @@ namespace Titanium.Web.Proxy.Compression
...
@@ -9,17 +9,9 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
/// </summary>
internal
class
GZipCompression
:
ICompression
internal
class
GZipCompression
:
ICompression
{
{
public
async
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
)
public
Stream
GetStream
(
Stream
stream
)
{
{
using
(
var
ms
=
new
MemoryStream
())
return
new
GZipStream
(
stream
,
CompressionMode
.
Compress
,
true
);
{
using
(
var
zip
=
new
GZipStream
(
ms
,
CompressionMode
.
Compress
,
true
))
{
await
zip
.
WriteAsync
(
responseBody
,
0
,
responseBody
.
Length
);
}
return
ms
.
ToArray
();
}
}
}
}
}
}
}
Titanium.Web.Proxy/Compression/ICompression.cs
View file @
5e1841ff
using
System.Threading.Tasks
;
using
System.IO
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Compression
namespace
Titanium.Web.Proxy.Compression
{
{
...
@@ -7,6 +8,6 @@ namespace Titanium.Web.Proxy.Compression
...
@@ -7,6 +8,6 @@ namespace Titanium.Web.Proxy.Compression
/// </summary>
/// </summary>
interface
ICompression
interface
ICompression
{
{
Task
<
byte
[
]>
Compress
(
byte
[]
responseBody
);
Stream
GetStream
(
Stream
stream
);
}
}
}
}
Titanium.Web.Proxy/Decompression/DecompressionFactory.cs
View file @
5e1841ff
namespace
Titanium.Web.Proxy.Decompression
using
System
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy.Decompression
{
{
/// <summary>
/// <summary>
/// A factory to generate the de-compression methods based on the type of compression
/// A factory to generate the de-compression methods based on the type of compression
/// </summary>
/// </summary>
internal
class
DecompressionFactory
internal
class
DecompressionFactory
{
{
internal
IDecompression
Create
(
string
type
)
//cache
private
static
readonly
Lazy
<
IDecompression
>
gzip
=
new
Lazy
<
IDecompression
>(()
=>
new
GZipDecompression
());
private
static
readonly
Lazy
<
IDecompression
>
deflate
=
new
Lazy
<
IDecompression
>(()
=>
new
DeflateDecompression
());
public
static
IDecompression
Create
(
string
type
)
{
{
switch
(
type
)
switch
(
type
)
{
{
case
"gzip"
:
case
KnownHeaders
.
ContentEncodingGzip
:
return
new
GZipDecompression
()
;
return
gzip
.
Value
;
case
"deflate"
:
case
KnownHeaders
.
ContentEncodingDeflate
:
return
new
DeflateDecompression
()
;
return
deflate
.
Value
;
default
:
default
:
return
new
DefaultDecompression
(
);
throw
new
Exception
(
$"Unsupported decompression mode:
{
type
}
"
);
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Decompression/DefaultDecompression.cs
deleted
100644 → 0
View file @
b27ba8cf
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Decompression
{
/// <summary>
/// When no compression is specified just return the byte array
/// </summary>
internal
class
DefaultDecompression
:
IDecompression
{
public
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
{
return
Task
.
FromResult
(
compressedArray
);
}
}
}
Titanium.Web.Proxy/Decompression/DeflateDecompression.cs
View file @
5e1841ff
...
@@ -10,30 +10,9 @@ namespace Titanium.Web.Proxy.Decompression
...
@@ -10,30 +10,9 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
/// </summary>
internal
class
DeflateDecompression
:
IDecompression
internal
class
DeflateDecompression
:
IDecompression
{
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
public
Stream
GetStream
(
Stream
stream
)
{
{
using
(
var
stream
=
new
MemoryStream
(
compressedArray
))
return
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
,
true
);
using
(
var
decompressor
=
new
DeflateStream
(
stream
,
CompressionMode
.
Decompress
))
{
var
buffer
=
BufferPool
.
GetBuffer
(
bufferSize
);
try
{
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
output
.
Write
(
buffer
,
0
,
read
);
}
return
output
.
ToArray
();
}
}
finally
{
BufferPool
.
ReturnBuffer
(
buffer
);
}
}
}
}
}
}
}
}
Titanium.Web.Proxy/Decompression/GZipDecompression.cs
View file @
5e1841ff
...
@@ -10,29 +10,9 @@ namespace Titanium.Web.Proxy.Decompression
...
@@ -10,29 +10,9 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
/// </summary>
internal
class
GZipDecompression
:
IDecompression
internal
class
GZipDecompression
:
IDecompression
{
{
public
async
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
)
public
Stream
GetStream
(
Stream
stream
)
{
{
using
(
var
decompressor
=
new
GZipStream
(
new
MemoryStream
(
compressedArray
),
CompressionMode
.
Decompress
))
return
new
GZipStream
(
stream
,
CompressionMode
.
Decompress
,
true
);
{
var
buffer
=
BufferPool
.
GetBuffer
(
bufferSize
);
try
{
using
(
var
output
=
new
MemoryStream
())
{
int
read
;
while
((
read
=
await
decompressor
.
ReadAsync
(
buffer
,
0
,
buffer
.
Length
))
>
0
)
{
output
.
Write
(
buffer
,
0
,
read
);
}
return
output
.
ToArray
();
}
}
finally
{
BufferPool
.
ReturnBuffer
(
buffer
);
}
}
}
}
}
}
}
}
Titanium.Web.Proxy/Decompression/IDecompression.cs
View file @
5e1841ff
using
System.Threading.Tasks
;
using
System.IO
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.Decompression
namespace
Titanium.Web.Proxy.Decompression
{
{
...
@@ -7,6 +8,6 @@ namespace Titanium.Web.Proxy.Decompression
...
@@ -7,6 +8,6 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary>
/// </summary>
internal
interface
IDecompression
internal
interface
IDecompression
{
{
Task
<
byte
[
]>
Decompress
(
byte
[]
compressedArray
,
int
bufferSize
);
Stream
GetStream
(
Stream
stream
);
}
}
}
}
Titanium.Web.Proxy/EventArguments/LimitedStream.cs
0 → 100644
View file @
5e1841ff
using
System
;
using
System.Collections.Generic
;
using
System.Globalization
;
using
System.IO
;
using
System.Threading.Tasks
;
using
StreamExtended.Helpers
;
using
StreamExtended.Network
;
namespace
Titanium.Web.Proxy.EventArguments
{
internal
class
LimitedStream
:
Stream
{
private
readonly
CustomBufferedStream
baseStream
;
private
readonly
CustomBinaryReader
baseReader
;
private
readonly
bool
isChunked
;
private
bool
readChunkTrail
;
private
long
bytesRemaining
;
public
LimitedStream
(
CustomBufferedStream
baseStream
,
CustomBinaryReader
baseReader
,
bool
isChunked
,
long
contentLength
)
{
this
.
baseStream
=
baseStream
;
this
.
baseReader
=
baseReader
;
this
.
isChunked
=
isChunked
;
bytesRemaining
=
isChunked
?
0
:
contentLength
;
}
private
void
GetNextChunk
()
{
if
(
readChunkTrail
)
{
// read the chunk trail of the previous chunk
string
s
=
baseReader
.
ReadLineAsync
().
Result
;
}
readChunkTrail
=
true
;
string
chunkHead
=
baseReader
.
ReadLineAsync
().
Result
;
int
idx
=
chunkHead
.
IndexOf
(
";"
);
if
(
idx
>=
0
)
{
// remove chunk extension
chunkHead
=
chunkHead
.
Substring
(
0
,
idx
);
}
int
chunkSize
=
int
.
Parse
(
chunkHead
,
NumberStyles
.
HexNumber
);
bytesRemaining
=
chunkSize
;
if
(
chunkSize
==
0
)
{
bytesRemaining
=
-
1
;
//chunk trail
string
s
=
baseReader
.
ReadLineAsync
().
Result
;
}
}
public
override
void
Flush
()
{
throw
new
NotSupportedException
();
}
public
override
long
Seek
(
long
offset
,
SeekOrigin
origin
)
{
throw
new
NotSupportedException
();
}
public
override
void
SetLength
(
long
value
)
{
throw
new
NotSupportedException
();
}
public
override
int
Read
(
byte
[]
buffer
,
int
offset
,
int
count
)
{
if
(
bytesRemaining
==
-
1
)
{
return
0
;
}
if
(
bytesRemaining
==
0
)
{
if
(
isChunked
)
{
GetNextChunk
();
}
else
{
bytesRemaining
=
-
1
;
}
}
if
(
bytesRemaining
==
-
1
)
{
return
0
;
}
int
toRead
=
(
int
)
Math
.
Min
(
count
,
bytesRemaining
);
int
res
=
baseStream
.
Read
(
buffer
,
offset
,
toRead
);
bytesRemaining
-=
res
;
return
res
;
}
public
async
Task
Finish
()
{
var
buffer
=
BufferPool
.
GetBuffer
(
baseReader
.
Buffer
.
Length
);
try
{
while
(
bytesRemaining
!=
-
1
)
{
await
ReadAsync
(
buffer
,
0
,
buffer
.
Length
);
}
}
finally
{
BufferPool
.
ReturnBuffer
(
buffer
);
}
}
public
override
void
Write
(
byte
[]
buffer
,
int
offset
,
int
count
)
{
throw
new
NotSupportedException
();
}
public
override
bool
CanRead
=>
true
;
public
override
bool
CanSeek
=>
false
;
public
override
bool
CanWrite
=>
false
;
public
override
long
Length
=>
throw
new
NotSupportedException
();
public
override
long
Position
{
get
=>
throw
new
NotSupportedException
();
set
=>
throw
new
NotSupportedException
();
}
}
}
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
5e1841ff
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Globalization
;
using
System.IO
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Reflection
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
StreamExtended.Helpers
;
using
StreamExtended.Helpers
;
using
StreamExtended.Network
;
using
StreamExtended.Network
;
...
@@ -100,6 +102,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -100,6 +102,8 @@ namespace Titanium.Web.Proxy.EventArguments
public
bool
IsTransparent
=>
LocalEndPoint
is
TransparentProxyEndPoint
;
public
bool
IsTransparent
=>
LocalEndPoint
is
TransparentProxyEndPoint
;
public
Exception
Exception
{
get
;
internal
set
;
}
/// <summary>
/// <summary>
/// Constructor to initialize the proxy
/// Constructor to initialize the proxy
/// </summary>
/// </summary>
...
@@ -146,7 +150,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -146,7 +150,7 @@ namespace Titanium.Web.Proxy.EventArguments
//If not already read (not cached yet)
//If not already read (not cached yet)
if
(!
request
.
IsBodyRead
)
if
(!
request
.
IsBodyRead
)
{
{
var
body
=
await
ReadBodyAsync
(
ProxyClient
.
ClientStreamReader
,
request
.
IsChunked
,
request
.
ContentLength
,
request
.
ContentEncoding
,
true
);
var
body
=
await
ReadBodyAsync
(
ProxyClient
.
ClientStreamReader
,
true
);
request
.
Body
=
body
;
request
.
Body
=
body
;
//Now set the flag to true
//Now set the flag to true
...
@@ -174,8 +178,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -174,8 +178,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
var
ex2
=
new
Exception
(
"Exception thrown in user event"
,
ex
);
exceptionFunc
(
new
Exception
(
"Exception thrown in user event"
,
ex
));
exceptionFunc
(
ex2
);
}
}
}
}
...
@@ -187,8 +190,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -187,8 +190,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
var
ex2
=
new
Exception
(
"Exception thrown in user event"
,
ex
);
exceptionFunc
(
new
Exception
(
"Exception thrown in user event"
,
ex
));
exceptionFunc
(
ex2
);
}
}
}
}
...
@@ -200,8 +202,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -200,8 +202,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
var
ex2
=
new
Exception
(
"Exception thrown in user event"
,
ex
);
exceptionFunc
(
new
Exception
(
"Exception thrown in user event"
,
ex
));
exceptionFunc
(
ex2
);
}
}
}
}
...
@@ -210,7 +211,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -210,7 +211,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
private
async
Task
ReadResponseBodyAsync
()
private
async
Task
ReadResponseBodyAsync
()
{
{
if
(!
WebSession
.
Request
.
Request
Locked
)
if
(!
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot read the response body before request is made to server."
);
throw
new
Exception
(
"You cannot read the response body before request is made to server."
);
}
}
...
@@ -224,7 +225,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -224,7 +225,7 @@ namespace Titanium.Web.Proxy.EventArguments
//If not already read (not cached yet)
//If not already read (not cached yet)
if
(!
response
.
IsBodyRead
)
if
(!
response
.
IsBodyRead
)
{
{
var
body
=
await
ReadBodyAsync
(
WebSession
.
ServerConnection
.
StreamReader
,
response
.
IsChunked
,
response
.
ContentLength
,
response
.
ContentEncoding
,
false
);
var
body
=
await
ReadBodyAsync
(
WebSession
.
ServerConnection
.
StreamReader
,
false
);
response
.
Body
=
body
;
response
.
Body
=
body
;
//Now set the flag to true
//Now set the flag to true
...
@@ -234,21 +235,21 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -234,21 +235,21 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
}
}
private
async
Task
<
byte
[
]>
ReadBodyAsync
(
CustomBinaryReader
reader
,
bool
is
Chunked
,
long
contentLength
,
string
contentEncoding
,
bool
is
Request
)
private
async
Task
<
byte
[
]>
ReadBodyAsync
(
CustomBinaryReader
reader
,
bool
isRequest
)
{
{
using
(
var
bodyStream
=
new
MemoryStream
())
using
(
var
bodyStream
=
new
MemoryStream
())
{
{
var
writer
=
new
HttpWriter
(
bodyStream
,
bufferSize
);
var
writer
=
new
HttpWriter
(
bodyStream
,
bufferSize
);
if
(
isRequest
)
if
(
isRequest
)
{
{
await
CopyRequestBodyAsync
(
writer
,
true
);
await
CopyRequestBodyAsync
(
writer
,
TransformationMode
.
Uncompress
);
}
}
else
else
{
{
await
CopyResponseBodyAsync
(
writer
,
true
);
await
CopyResponseBodyAsync
(
writer
,
TransformationMode
.
Uncompress
);
}
}
return
await
GetDecompressedBodyAsync
(
contentEncoding
,
bodyStream
.
ToArray
()
);
return
bodyStream
.
ToArray
(
);
}
}
}
}
...
@@ -256,7 +257,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -256,7 +257,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// This is called when the request is PUT/POST/PATCH to read the body
/// This is called when the request is PUT/POST/PATCH to read the body
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
internal
async
Task
CopyRequestBodyAsync
(
HttpWriter
writer
,
bool
removeChunkedEncoding
)
internal
async
Task
CopyRequestBodyAsync
(
HttpWriter
writer
,
TransformationMode
transformation
)
{
{
// End the operation
// End the operation
var
request
=
WebSession
.
Request
;
var
request
=
WebSession
.
Request
;
...
@@ -293,16 +294,56 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -293,16 +294,56 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
else
else
{
{
await
writer
.
CopyBodyAsync
(
reader
,
request
.
IsChunked
,
contentLength
,
removeChunkedEncoding
);
await
CopyBodyAsync
(
ProxyClient
.
ClientStream
,
reader
,
writer
,
request
,
transformation
,
OnDataSent
);
}
}
}
}
internal
async
Task
CopyResponseBodyAsync
(
HttpWriter
writer
,
bool
removeChunkedEncoding
)
internal
async
Task
CopyResponseBodyAsync
(
HttpWriter
writer
,
TransformationMode
transformation
)
{
{
var
response
=
WebSession
.
Response
;
var
response
=
WebSession
.
Response
;
var
reader
=
WebSession
.
ServerConnection
.
StreamReader
;
var
reader
=
WebSession
.
ServerConnection
.
StreamReader
;
await
writer
.
CopyBodyAsync
(
reader
,
response
.
IsChunked
,
response
.
ContentLength
,
removeChunkedEncoding
);
await
CopyBodyAsync
(
WebSession
.
ServerConnection
.
Stream
,
reader
,
writer
,
response
,
transformation
,
OnDataReceived
);
}
private
async
Task
CopyBodyAsync
(
CustomBufferedStream
stream
,
CustomBinaryReader
reader
,
HttpWriter
writer
,
RequestResponseBase
requestResponse
,
TransformationMode
transformation
,
Action
<
byte
[],
int
,
int
>
onCopy
)
{
bool
isChunked
=
requestResponse
.
IsChunked
;
long
contentLength
=
requestResponse
.
ContentLength
;
if
(
transformation
==
TransformationMode
.
None
)
{
await
writer
.
CopyBodyAsync
(
reader
,
isChunked
,
contentLength
,
onCopy
);
return
;
}
LimitedStream
limitedStream
;
Stream
decompressStream
=
null
;
string
contentEncoding
=
requestResponse
.
ContentEncoding
;
Stream
s
=
limitedStream
=
new
LimitedStream
(
stream
,
reader
,
isChunked
,
contentLength
);
if
(
transformation
==
TransformationMode
.
Uncompress
&&
contentEncoding
!=
null
)
{
s
=
decompressStream
=
DecompressionFactory
.
Create
(
contentEncoding
).
GetStream
(
s
);
}
try
{
var
bufStream
=
new
CustomBufferedStream
(
s
,
bufferSize
,
true
);
reader
=
new
CustomBinaryReader
(
bufStream
,
bufferSize
);
await
writer
.
CopyBodyAsync
(
reader
,
false
,
-
1
,
onCopy
);
}
finally
{
reader
?.
Dispose
();
decompressStream
?.
Dispose
();
await
limitedStream
.
Finish
();
limitedStream
.
Dispose
();
}
}
}
/// <summary>
/// <summary>
...
@@ -401,19 +442,20 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -401,19 +442,20 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetRequestBody
(
byte
[]
body
)
public
async
Task
SetRequestBody
(
byte
[]
body
)
{
{
if
(
WebSession
.
Request
.
RequestLocked
)
var
request
=
WebSession
.
Request
;
if
(
request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
}
}
//syphon out the request body from client before setting the new body
//syphon out the request body from client before setting the new body
if
(!
WebSession
.
R
equest
.
IsBodyRead
)
if
(!
r
equest
.
IsBodyRead
)
{
{
await
ReadRequestBodyAsync
();
await
ReadRequestBodyAsync
();
}
}
WebSession
.
R
equest
.
Body
=
body
;
r
equest
.
Body
=
body
;
WebSession
.
Request
.
ContentLength
=
WebSession
.
Request
.
IsChunked
?
-
1
:
body
.
Length
;
request
.
UpdateContentLength
()
;
}
}
/// <summary>
/// <summary>
...
@@ -422,7 +464,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -422,7 +464,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetRequestBodyString
(
string
body
)
public
async
Task
SetRequestBodyString
(
string
body
)
{
{
if
(
WebSession
.
Request
.
Request
Locked
)
if
(
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
}
}
...
@@ -470,28 +512,23 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -470,28 +512,23 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetResponseBody
(
byte
[]
body
)
public
async
Task
SetResponseBody
(
byte
[]
body
)
{
{
if
(!
WebSession
.
Request
.
Request
Locked
)
if
(!
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
}
}
var
response
=
WebSession
.
Response
;
//syphon out the response body from server before setting the new body
//syphon out the response body from server before setting the new body
if
(
WebSession
.
R
esponse
.
Body
==
null
)
if
(
r
esponse
.
Body
==
null
)
{
{
await
GetResponseBody
();
await
GetResponseBody
();
}
}
WebSession
.
R
esponse
.
Body
=
body
;
r
esponse
.
Body
=
body
;
//If there is a content length header update it
//If there is a content length header update it
if
(
WebSession
.
Response
.
IsChunked
==
false
)
response
.
UpdateContentLength
();
{
WebSession
.
Response
.
ContentLength
=
body
.
Length
;
}
else
{
WebSession
.
Response
.
ContentLength
=
-
1
;
}
}
}
/// <summary>
/// <summary>
...
@@ -500,7 +537,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -500,7 +537,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetResponseBodyString
(
string
body
)
public
async
Task
SetResponseBodyString
(
string
body
)
{
{
if
(!
WebSession
.
Request
.
Request
Locked
)
if
(!
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
throw
new
Exception
(
"You cannot call this function before request is made to server."
);
}
}
...
@@ -516,14 +553,6 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -516,14 +553,6 @@ namespace Titanium.Web.Proxy.EventArguments
await
SetResponseBody
(
bodyBytes
);
await
SetResponseBody
(
bodyBytes
);
}
}
private
async
Task
<
byte
[
]>
GetDecompressedBodyAsync
(
string
encodingType
,
byte
[]
bodyStream
)
{
var
decompressionFactory
=
new
DecompressionFactory
();
var
decompressor
=
decompressionFactory
.
Create
(
encodingType
);
return
await
decompressor
.
Decompress
(
bodyStream
,
bufferSize
);
}
/// <summary>
/// <summary>
/// Before request is made to server
/// Before request is made to server
/// Respond with the specified HTML string to client
/// Respond with the specified HTML string to client
...
@@ -620,14 +649,14 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -620,14 +649,14 @@ namespace Titanium.Web.Proxy.EventArguments
/// a generic responder method
/// a generic responder method
public
void
Respond
(
Response
response
)
public
void
Respond
(
Response
response
)
{
{
if
(
WebSession
.
Request
.
Request
Locked
)
if
(
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
}
}
WebSession
.
Request
.
Request
Locked
=
true
;
WebSession
.
Request
.
Locked
=
true
;
response
.
Response
Locked
=
true
;
response
.
Locked
=
true
;
response
.
IsBodyRead
=
true
;
response
.
IsBodyRead
=
true
;
WebSession
.
Response
=
response
;
WebSession
.
Response
=
response
;
...
@@ -645,6 +674,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -645,6 +674,7 @@ namespace Titanium.Web.Proxy.EventArguments
DataSent
=
null
;
DataSent
=
null
;
DataReceived
=
null
;
DataReceived
=
null
;
MultipartRequestPartSent
=
null
;
MultipartRequestPartSent
=
null
;
Exception
=
null
;
WebSession
.
FinishSession
();
WebSession
.
FinishSession
();
}
}
...
...
Titanium.Web.Proxy/EventArguments/TransformationMode.cs
0 → 100644
View file @
5e1841ff
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.EventArguments
{
internal
enum
TransformationMode
{
None
,
/// <summary>
/// Removes the chunked encoding
/// </summary>
RemoveChunked
,
/// <summary>
/// Uncompress the body (this also removes the chunked encoding if exists)
/// </summary>
Uncompress
,
}
}
Titanium.Web.Proxy/Helpers/HttpWriter.cs
View file @
5e1841ff
...
@@ -5,6 +5,7 @@ using System.Text;
...
@@ -5,6 +5,7 @@ using System.Text;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
StreamExtended.Helpers
;
using
StreamExtended.Helpers
;
using
StreamExtended.Network
;
using
StreamExtended.Network
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Shared
;
...
@@ -152,26 +153,26 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -152,26 +153,26 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="streamReader"></param>
/// <param name="streamReader"></param>
/// <param name="isChunked"></param>
/// <param name="isChunked"></param>
/// <param name="contentLength"></param>
/// <param name="contentLength"></param>
/// <param name="
removeChunkedEncoding
"></param>
/// <param name="
onCopy
"></param>
/// <returns></returns>
/// <returns></returns>
internal
Task
CopyBodyAsync
(
CustomBinaryReader
streamReader
,
bool
isChunked
,
long
contentLength
,
bool
removeChunkedEncoding
)
internal
Task
CopyBodyAsync
(
CustomBinaryReader
streamReader
,
bool
isChunked
,
long
contentLength
,
Action
<
byte
[],
int
,
int
>
onCopy
)
{
{
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if
(
isChunked
)
if
(
isChunked
)
{
{
//Need to revist, find any potential bugs
//Need to revist, find any potential bugs
//send the body bytes to server in chunks
//send the body bytes to server in chunks
return
CopyBodyChunkedAsync
(
streamReader
,
removeChunkedEncoding
);
return
CopyBodyChunkedAsync
(
streamReader
,
onCopy
);
}
}
//http 1.0
//http 1.0
or the stream reader limits the stream
if
(
contentLength
==
-
1
)
if
(
contentLength
==
-
1
)
{
{
contentLength
=
long
.
MaxValue
;
contentLength
=
long
.
MaxValue
;
}
}
//If not chunked then its easy just read the amount of bytes mentioned in content length header
//If not chunked then its easy just read the amount of bytes mentioned in content length header
return
CopyBytesFromStream
(
streamReader
,
contentLength
);
return
CopyBytesFromStream
(
streamReader
,
contentLength
,
onCopy
);
}
}
/// <summary>
/// <summary>
...
@@ -196,29 +197,30 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -196,29 +197,30 @@ namespace Titanium.Web.Proxy.Helpers
/// Copies the streams chunked
/// Copies the streams chunked
/// </summary>
/// </summary>
/// <param name="reader"></param>
/// <param name="reader"></param>
/// <param name="
removeChunkedEncoding
"></param>
/// <param name="
onCopy
"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
CopyBodyChunkedAsync
(
CustomBinaryReader
reader
,
bool
removeChunkedEncoding
)
private
async
Task
CopyBodyChunkedAsync
(
CustomBinaryReader
reader
,
Action
<
byte
[],
int
,
int
>
onCopy
)
{
{
while
(
true
)
while
(
true
)
{
{
string
chunkHead
=
await
reader
.
ReadLineAsync
();
string
chunkHead
=
await
reader
.
ReadLineAsync
();
int
chunkSize
=
int
.
Parse
(
chunkHead
,
NumberStyles
.
HexNumber
);
int
idx
=
chunkHead
.
IndexOf
(
";"
);
if
(
idx
>=
0
)
if
(!
removeChunkedEncoding
)
{
{
await
WriteLineAsync
(
chunkHead
);
// remove chunk extension
chunkHead
=
chunkHead
.
Substring
(
0
,
idx
);
}
}
int
chunkSize
=
int
.
Parse
(
chunkHead
,
NumberStyles
.
HexNumber
);
await
WriteLineAsync
(
chunkHead
);
if
(
chunkSize
!=
0
)
if
(
chunkSize
!=
0
)
{
{
await
CopyBytesFromStream
(
reader
,
chunkSize
);
await
CopyBytesFromStream
(
reader
,
chunkSize
,
onCopy
);
}
}
if
(!
removeChunkedEncoding
)
await
WriteLineAsync
();
{
await
WriteLineAsync
();
}
//chunk trail
//chunk trail
await
reader
.
ReadLineAsync
();
await
reader
.
ReadLineAsync
();
...
@@ -235,8 +237,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -235,8 +237,9 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// </summary>
/// <param name="reader"></param>
/// <param name="reader"></param>
/// <param name="count"></param>
/// <param name="count"></param>
/// <param name="onCopy"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
CopyBytesFromStream
(
CustomBinaryReader
reader
,
long
count
)
private
async
Task
CopyBytesFromStream
(
CustomBinaryReader
reader
,
long
count
,
Action
<
byte
[],
int
,
int
>
onCopy
)
{
{
var
buffer
=
reader
.
Buffer
;
var
buffer
=
reader
.
Buffer
;
long
remainingBytes
=
count
;
long
remainingBytes
=
count
;
...
@@ -258,6 +261,8 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -258,6 +261,8 @@ namespace Titanium.Web.Proxy.Helpers
remainingBytes
-=
bytesRead
;
remainingBytes
-=
bytesRead
;
await
WriteAsync
(
buffer
,
0
,
bytesRead
);
await
WriteAsync
(
buffer
,
0
,
bytesRead
);
onCopy
?.
Invoke
(
buffer
,
0
,
bytesRead
);
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/Helpers/SystemProxy.cs
View file @
5e1841ff
...
@@ -46,7 +46,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -46,7 +46,7 @@ namespace Titanium.Web.Proxy.Helpers
protocol
=
ProxyServer
.
UriSchemeHttp
;
protocol
=
ProxyServer
.
UriSchemeHttp
;
break
;
break
;
case
ProxyProtocolType
.
Https
:
case
ProxyProtocolType
.
Https
:
protocol
=
Proxy
.
Proxy
Server
.
UriSchemeHttps
;
protocol
=
ProxyServer
.
UriSchemeHttps
;
break
;
break
;
default
:
default
:
throw
new
Exception
(
"Unsupported protocol type"
);
throw
new
Exception
(
"Unsupported protocol type"
);
...
...
Titanium.Web.Proxy/Http/ConnectResponse.cs
View file @
5e1841ff
...
@@ -22,7 +22,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -22,7 +22,6 @@ namespace Titanium.Web.Proxy.Http
StatusDescription
=
"Connection Established"
StatusDescription
=
"Connection Established"
};
};
response
.
Headers
.
AddHeader
(
KnownHeaders
.
Timestamp
,
DateTime
.
Now
.
ToString
());
return
response
;
return
response
;
}
}
}
}
...
...
Titanium.Web.Proxy/Http/KnownHeaders.cs
View file @
5e1841ff
...
@@ -40,6 +40,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -40,6 +40,8 @@ namespace Titanium.Web.Proxy.Http
// Response headers
// Response headers
public
const
string
ContentEncoding
=
"content-encoding"
;
public
const
string
ContentEncoding
=
"content-encoding"
;
public
const
string
ContentEncodingDeflate
=
"deflate"
;
public
const
string
ContentEncodingGzip
=
"gzip"
;
public
const
string
Location
=
"Location"
;
public
const
string
Location
=
"Location"
;
...
@@ -47,8 +49,5 @@ namespace Titanium.Web.Proxy.Http
...
@@ -47,8 +49,5 @@ namespace Titanium.Web.Proxy.Http
public
const
string
TransferEncoding
=
"transfer-encoding"
;
public
const
string
TransferEncoding
=
"transfer-encoding"
;
public
const
string
TransferEncodingChunked
=
"chunked"
;
public
const
string
TransferEncodingChunked
=
"chunked"
;
// ???
public
const
string
Timestamp
=
"Timestamp"
;
}
}
}
}
Titanium.Web.Proxy/Http/Request.cs
View file @
5e1841ff
...
@@ -3,28 +3,17 @@ using System.ComponentModel;
...
@@ -3,28 +3,17 @@ using System.ComponentModel;
using
System.Text
;
using
System.Text
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.Http
namespace
Titanium.Web.Proxy.Http
{
{
/// <summary>
/// <summary>
///
A HTTP(S
) request object
///
Http(s
) request object
/// </summary>
/// </summary>
[
TypeConverter
(
typeof
(
ExpandableObjectConverter
))]
[
TypeConverter
(
typeof
(
ExpandableObjectConverter
))]
public
class
Request
public
class
Request
:
RequestResponseBase
{
{
/// <summary>
/// Cached request body as byte array
/// </summary>
private
byte
[]
body
;
/// <summary>
/// Cached request body as string
/// </summary>
private
string
bodyString
;
/// <summary>
/// <summary>
/// Request Method
/// Request Method
/// </summary>
/// </summary>
...
@@ -45,16 +34,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -45,16 +34,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
string
OriginalUrl
{
get
;
set
;
}
public
string
OriginalUrl
{
get
;
set
;
}
/// <summary>
/// Request Http Version
/// </summary>
public
Version
HttpVersion
{
get
;
set
;
}
/// <summary>
/// Keeps the request body data after the session is finished
/// </summary>
public
bool
KeepBody
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Has request body?
/// Has request body?
/// </summary>
/// </summary>
...
@@ -97,80 +76,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -97,80 +76,6 @@ namespace Titanium.Web.Proxy.Http
set
=>
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
Host
,
value
);
set
=>
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
Host
,
value
);
}
}
/// <summary>
/// Content encoding header value
/// </summary>
public
string
ContentEncoding
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentEncoding
);
/// <summary>
/// Request content-length
/// </summary>
public
long
ContentLength
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentLength
);
if
(
headerValue
==
null
)
{
return
-
1
;
}
long
.
TryParse
(
headerValue
,
out
long
contentLen
);
if
(
contentLen
>=
0
)
{
return
contentLen
;
}
return
-
1
;
}
set
{
if
(
value
>=
0
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
ContentLength
,
value
.
ToString
());
IsChunked
=
false
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
ContentLength
);
}
}
}
/// <summary>
/// Request content-type
/// </summary>
public
string
ContentType
{
get
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentType
);
set
=>
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
ContentType
,
value
);
}
/// <summary>
/// Is request body send as chunked bytes
/// </summary>
public
bool
IsChunked
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
);
}
set
{
if
(
value
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
TransferEncoding
,
KnownHeaders
.
TransferEncodingChunked
);
ContentLength
=
-
1
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
TransferEncoding
);
}
}
}
/// <summary>
/// <summary>
/// Does this request has a 100-continue header?
/// Does this request has a 100-continue header?
/// </summary>
/// </summary>
...
@@ -190,17 +95,12 @@ namespace Titanium.Web.Proxy.Http
...
@@ -190,17 +95,12 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
string
Url
=>
RequestUri
.
OriginalString
;
public
string
Url
=>
RequestUri
.
OriginalString
;
/// <summary>
/// Encoding for this request
/// </summary>
public
Encoding
Encoding
=>
HttpHelper
.
GetEncodingFromContentType
(
ContentType
);
/// <summary>
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request
/// Terminates the underlying Tcp Connection to client after current request
/// </summary>
/// </summary>
internal
bool
CancelRequest
{
get
;
set
;
}
internal
bool
CancelRequest
{
get
;
set
;
}
internal
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
{
{
//GET request don't have a request body to read
//GET request don't have a request body to read
if
(!
HasBody
)
if
(!
HasBody
)
...
@@ -211,7 +111,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -211,7 +111,7 @@ namespace Titanium.Web.Proxy.Http
if
(!
IsBodyRead
)
if
(!
IsBodyRead
)
{
{
if
(
Request
Locked
)
if
(
Locked
)
{
{
throw
new
Exception
(
"You cannot get the request body after request is made to server."
);
throw
new
Exception
(
"You cannot get the request body after request is made to server."
);
}
}
...
@@ -225,41 +125,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -225,41 +125,6 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request body as byte array
/// </summary>
[
Browsable
(
false
)]
public
byte
[]
Body
{
get
{
EnsureBodyAvailable
();
return
body
;
}
internal
set
{
body
=
value
;
bodyString
=
null
;
}
}
/// <summary>
/// Request body as string
/// Use the encoding specified in request to decode the byte[] data to string
/// </summary>
[
Browsable
(
false
)]
public
string
BodyString
=>
bodyString
??
(
bodyString
=
Encoding
.
GetString
(
Body
));
/// <summary>
/// Request body was read by user?
/// </summary>
public
bool
IsBodyRead
{
get
;
internal
set
;
}
/// <summary>
/// Request is ready to be sent (user callbacks are complete?)
/// </summary>
internal
bool
RequestLocked
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Does this request has an upgrade to websocket header?
/// Does this request has an upgrade to websocket header?
/// </summary>
/// </summary>
...
@@ -278,11 +143,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -278,11 +143,6 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Request header collection
/// </summary>
public
HeaderCollection
Headers
{
get
;
}
=
new
HeaderCollection
();
/// <summary>
/// <summary>
/// Does server responsed positively for 100 continue request
/// Does server responsed positively for 100 continue request
/// </summary>
/// </summary>
...
@@ -296,7 +156,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -296,7 +156,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Gets the header text.
/// Gets the header text.
/// </summary>
/// </summary>
public
string
HeaderText
public
override
string
HeaderText
{
{
get
get
{
{
...
@@ -367,22 +227,5 @@ namespace Titanium.Web.Proxy.Http
...
@@ -367,22 +227,5 @@ namespace Titanium.Web.Proxy.Http
return
true
;
return
true
;
}
}
/// <summary>
/// Finish the session
/// </summary>
public
void
FinishSession
()
{
if
(!
KeepBody
)
{
body
=
null
;
bodyString
=
null
;
}
}
public
override
string
ToString
()
{
return
HeaderText
;
}
}
}
}
}
Titanium.Web.Proxy/Http/RequestResponseBase.cs
0 → 100644
View file @
5e1841ff
using
System
;
using
System.Collections.Generic
;
using
System.ComponentModel
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
namespace
Titanium.Web.Proxy.Http
{
public
abstract
class
RequestResponseBase
{
/// <summary>
/// Cached body content as byte array
/// </summary>
private
byte
[]
body
;
/// <summary>
/// Cached body as string
/// </summary>
private
string
bodyString
;
/// <summary>
/// Keeps the body data after the session is finished
/// </summary>
public
bool
KeepBody
{
get
;
set
;
}
/// <summary>
/// Http Version
/// </summary>
public
Version
HttpVersion
{
get
;
set
;
}
=
HttpHeader
.
VersionUnknown
;
/// <summary>
/// Collection of all headers
/// </summary>
public
HeaderCollection
Headers
{
get
;
}
=
new
HeaderCollection
();
/// <summary>
/// Length of the body
/// </summary>
public
long
ContentLength
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentLength
);
if
(
headerValue
==
null
)
{
return
-
1
;
}
if
(
long
.
TryParse
(
headerValue
,
out
long
contentLen
)
&&
contentLen
>=
0
)
{
return
contentLen
;
}
return
-
1
;
}
set
{
if
(
value
>=
0
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
ContentLength
,
value
.
ToString
());
IsChunked
=
false
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
ContentLength
);
}
}
}
/// <summary>
/// Content encoding for this request/response
/// </summary>
public
string
ContentEncoding
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentEncoding
)?.
Trim
();
/// <summary>
/// Encoding for this request/response
/// </summary>
public
Encoding
Encoding
=>
HttpHelper
.
GetEncodingFromContentType
(
ContentType
);
/// <summary>
/// Content-type of the request/response
/// </summary>
public
string
ContentType
{
get
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentType
);
set
=>
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
ContentType
,
value
);
}
/// <summary>
/// Is body send as chunked bytes
/// </summary>
public
bool
IsChunked
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
);
}
set
{
if
(
value
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
TransferEncoding
,
KnownHeaders
.
TransferEncodingChunked
);
ContentLength
=
-
1
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
TransferEncoding
);
}
}
}
public
abstract
string
HeaderText
{
get
;
}
/// <summary>
/// Body as byte array
/// </summary>
[
Browsable
(
false
)]
public
byte
[]
Body
{
get
{
EnsureBodyAvailable
();
return
body
;
}
internal
set
{
body
=
value
;
bodyString
=
null
;
}
}
internal
abstract
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
);
/// <summary>
/// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// </summary>
[
Browsable
(
false
)]
public
string
BodyString
=>
bodyString
??
(
bodyString
=
Encoding
.
GetString
(
Body
));
/// <summary>
/// Was the body read by user?
/// </summary>
public
bool
IsBodyRead
{
get
;
internal
set
;
}
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// </summary>
internal
bool
Locked
{
get
;
set
;
}
internal
void
UpdateContentLength
()
{
ContentLength
=
IsChunked
?
-
1
:
body
.
Length
;
}
/// <summary>
/// Finish the session
/// </summary>
internal
void
FinishSession
()
{
if
(!
KeepBody
)
{
body
=
null
;
bodyString
=
null
;
}
}
public
override
string
ToString
()
{
return
HeaderText
;
}
}
}
Titanium.Web.Proxy/Http/Response.cs
View file @
5e1841ff
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
using
System.ComponentModel
;
using
System.ComponentModel
;
using
System.Text
;
using
System.Text
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Shared
;
...
@@ -12,18 +11,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -12,18 +11,8 @@ namespace Titanium.Web.Proxy.Http
/// Http(s) response object
/// Http(s) response object
/// </summary>
/// </summary>
[
TypeConverter
(
typeof
(
ExpandableObjectConverter
))]
[
TypeConverter
(
typeof
(
ExpandableObjectConverter
))]
public
class
Response
public
class
Response
:
RequestResponseBase
{
{
/// <summary>
/// Cached response body content as byte array
/// </summary>
private
byte
[]
body
;
/// <summary>
/// Cached response body as string
/// </summary>
private
string
bodyString
;
/// <summary>
/// <summary>
/// Response Status Code.
/// Response Status Code.
/// </summary>
/// </summary>
...
@@ -34,26 +23,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -34,26 +23,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
string
StatusDescription
{
get
;
set
;
}
public
string
StatusDescription
{
get
;
set
;
}
/// <summary>
/// Encoding used in response
/// </summary>
public
Encoding
Encoding
=>
HttpHelper
.
GetEncodingFromContentType
(
ContentType
);
/// <summary>
/// Content encoding for this response
/// </summary>
public
string
ContentEncoding
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentEncoding
)?.
Trim
();
/// <summary>
/// Http version
/// </summary>
public
Version
HttpVersion
{
get
;
set
;
}
=
HttpHeader
.
VersionUnknown
;
/// <summary>
/// Keeps the response body data after the session is finished
/// </summary>
public
bool
KeepBody
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Has response body?
/// Has response body?
/// </summary>
/// </summary>
...
@@ -108,78 +77,9 @@ namespace Titanium.Web.Proxy.Http
...
@@ -108,78 +77,9 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
/// Content type of this response
/// </summary>
public
string
ContentType
=>
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentType
);
/// <summary>
/// Length of response body
/// </summary>
public
long
ContentLength
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
ContentLength
);
if
(
headerValue
==
null
)
{
return
-
1
;
}
if
(
long
.
TryParse
(
headerValue
,
out
long
contentLen
))
{
return
contentLen
;
}
return
-
1
;
}
set
{
if
(
value
>=
0
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
ContentLength
,
value
.
ToString
());
IsChunked
=
false
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
ContentLength
);
}
}
}
/// <summary>
/// Response transfer-encoding is chunked?
/// </summary>
public
bool
IsChunked
{
get
{
string
headerValue
=
Headers
.
GetHeaderValueOrNull
(
KnownHeaders
.
TransferEncoding
);
return
headerValue
!=
null
&&
headerValue
.
ContainsIgnoreCase
(
KnownHeaders
.
TransferEncodingChunked
);
}
set
{
if
(
value
)
{
Headers
.
SetOrAddHeaderValue
(
KnownHeaders
.
TransferEncoding
,
KnownHeaders
.
TransferEncodingChunked
);
ContentLength
=
-
1
;
}
else
{
Headers
.
RemoveHeader
(
KnownHeaders
.
TransferEncoding
);
}
}
}
/// <summary>
/// Collection of all response headers
/// </summary>
public
HeaderCollection
Headers
{
get
;
}
=
new
HeaderCollection
();
internal
void
EnsureBodyAvailable
()
{
{
if
(!
IsBodyRead
)
if
(!
IsBodyRead
&&
throwWhenNotReadYet
)
{
{
throw
new
Exception
(
"Response body is not read yet. "
+
throw
new
Exception
(
"Response body is not read yet. "
+
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() "
+
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() "
+
...
@@ -187,41 +87,6 @@ namespace Titanium.Web.Proxy.Http
...
@@ -187,41 +87,6 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Response body as byte array
/// </summary>
[
Browsable
(
false
)]
public
byte
[]
Body
{
get
{
EnsureBodyAvailable
();
return
body
;
}
internal
set
{
body
=
value
;
bodyString
=
null
;
}
}
/// <summary>
/// Response body as string
/// Use the encoding specified in response to decode the byte[] data to string
/// </summary>
[
Browsable
(
false
)]
public
string
BodyString
=>
bodyString
??
(
bodyString
=
Encoding
.
GetString
(
Body
));
/// <summary>
/// Was response body read by user
/// </summary>
public
bool
IsBodyRead
{
get
;
internal
set
;
}
/// <summary>
/// Is response is no more modifyable by user (user callbacks complete?)
/// </summary>
internal
bool
ResponseLocked
{
get
;
set
;
}
/// <summary>
/// <summary>
/// Is response 100-continue
/// Is response 100-continue
/// </summary>
/// </summary>
...
@@ -240,7 +105,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -240,7 +105,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Gets the header text.
/// Gets the header text.
/// </summary>
/// </summary>
public
string
HeaderText
public
override
string
HeaderText
{
{
get
get
{
{
...
@@ -280,22 +145,5 @@ namespace Titanium.Web.Proxy.Http
...
@@ -280,22 +145,5 @@ namespace Titanium.Web.Proxy.Http
statusCode
=
int
.
Parse
(
httpResult
[
1
]);
statusCode
=
int
.
Parse
(
httpResult
[
1
]);
statusDescription
=
httpResult
[
2
];
statusDescription
=
httpResult
[
2
];
}
}
/// <summary>
/// Finish the session
/// </summary>
internal
void
FinishSession
()
{
if
(!
KeepBody
)
{
body
=
null
;
bodyString
=
null
;
}
}
public
override
string
ToString
()
{
return
HeaderText
;
}
}
}
}
}
Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs
View file @
5e1841ff
...
@@ -233,7 +233,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -233,7 +233,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
exceptionFunc
.
Invoke
(
new
Exception
(
"Failed to create BC certificate"
,
ex
));
exceptionFunc
(
new
Exception
(
"Failed to create BC certificate"
,
ex
));
}
}
if
(!
cancellationToken
.
IsCancellationRequested
)
if
(!
cancellationToken
.
IsCancellationRequested
)
...
...
Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs
View file @
5e1841ff
...
@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
...
@@ -271,7 +271,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
exceptionFunc
.
Invoke
(
new
Exception
(
"Failed to create Win certificate"
,
ex
));
exceptionFunc
(
new
Exception
(
"Failed to create Win certificate"
,
ex
));
}
}
if
(!
cancellationToken
.
IsCancellationRequested
)
if
(!
cancellationToken
.
IsCancellationRequested
)
...
...
Titanium.Web.Proxy/ProxyServer.cs
View file @
5e1841ff
...
@@ -189,6 +189,11 @@ namespace Titanium.Web.Proxy
...
@@ -189,6 +189,11 @@ namespace Titanium.Web.Proxy
/// </summary>
/// </summary>
public
event
AsyncEventHandler
<
SessionEventArgs
>
BeforeResponse
;
public
event
AsyncEventHandler
<
SessionEventArgs
>
BeforeResponse
;
/// <summary>
/// Intercept after response from server
/// </summary>
public
event
AsyncEventHandler
<
SessionEventArgs
>
AfterResponse
;
/// <summary>
/// <summary>
/// Callback for error events in proxy
/// Callback for error events in proxy
/// </summary>
/// </summary>
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
5e1841ff
...
@@ -308,158 +308,168 @@ namespace Titanium.Web.Proxy
...
@@ -308,158 +308,168 @@ namespace Titanium.Web.Proxy
try
try
{
{
Request
.
ParseRequestLine
(
httpCmd
,
out
string
httpMethod
,
out
string
httpUrl
,
out
var
version
);
try
{
Request
.
ParseRequestLine
(
httpCmd
,
out
string
httpMethod
,
out
string
httpUrl
,
out
var
version
);
//Read the request headers in to unique and non-unique header collections
//Read the request headers in to unique and non-unique header collections
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
Headers
);
await
HeaderParser
.
ReadHeaders
(
clientStreamReader
,
args
.
WebSession
.
Request
.
Headers
);
Uri
httpRemoteUri
;
Uri
httpRemoteUri
;
if
(
uriSchemeRegex
.
IsMatch
(
httpUrl
))
if
(
uriSchemeRegex
.
IsMatch
(
httpUrl
))
{
try
{
{
httpRemoteUri
=
new
Uri
(
httpUrl
);
try
{
httpRemoteUri
=
new
Uri
(
httpUrl
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
httpUrl
}
'"
,
ex
);
}
}
}
catch
(
Exception
ex
)
else
{
{
throw
new
Exception
(
$"Invalid URI: '
{
httpUrl
}
'"
,
ex
);
string
host
=
args
.
WebSession
.
Request
.
Host
??
httpsConnectHostname
;
string
hostAndPath
=
host
;
if
(
httpUrl
.
StartsWith
(
"/"
))
{
hostAndPath
+=
httpUrl
;
}
string
url
=
string
.
Concat
(
httpsConnectHostname
==
null
?
"http://"
:
"https://"
,
hostAndPath
);
try
{
httpRemoteUri
=
new
Uri
(
url
);
}
catch
(
Exception
ex
)
{
throw
new
Exception
(
$"Invalid URI: '
{
url
}
'"
,
ex
);
}
}
}
}
else
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
{
args
.
WebSession
.
Request
.
OriginalUrl
=
httpUrl
;
string
host
=
args
.
WebSession
.
Request
.
Host
??
httpsConnectHostname
;
string
hostAndPath
=
host
;
args
.
WebSession
.
Request
.
Method
=
httpMethod
;
if
(
httpUrl
.
StartsWith
(
"/"
))
args
.
WebSession
.
Request
.
HttpVersion
=
version
;
args
.
ProxyClient
.
ClientStream
=
clientStream
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
//proxy authorization check
if
(!
args
.
IsTransparent
&&
httpsConnectHostname
==
null
&&
await
CheckAuthorization
(
args
)
==
false
)
{
{
hostAndPath
+=
httpUrl
;
await
InvokeBeforeResponse
(
args
);
//send the response
await
clientStreamWriter
.
WriteResponseAsync
(
args
.
WebSession
.
Response
);
break
;
}
}
string
url
=
string
.
Concat
(
httpsConnectHostname
==
null
?
"http://"
:
"https://"
,
hostAndPath
);
if
(!
isTransparentEndPoint
)
try
{
{
httpRemoteUri
=
new
Uri
(
url
);
PrepareRequestHeaders
(
args
.
WebSession
.
Request
.
Headers
);
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
Request
.
RequestUri
.
Authority
;
}
}
catch
(
Exception
ex
)
//if win auth is enabled
//we need a cache of request body
//so that we can send it after authentication in WinAuthHandler.cs
if
(
isWindowsAuthenticationEnabledAndSupported
&&
args
.
WebSession
.
Request
.
HasBody
)
{
{
throw
new
Exception
(
$"Invalid URI: '
{
url
}
'"
,
ex
);
await
args
.
GetRequestBody
(
);
}
}
}
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
args
.
WebSession
.
Request
.
OriginalUrl
=
httpUrl
;
args
.
WebSession
.
Request
.
Method
=
httpMethod
;
args
.
WebSession
.
Request
.
HttpVersion
=
version
;
args
.
ProxyClient
.
ClientStream
=
clientStream
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
//proxy authorization check
if
(!
args
.
IsTransparent
&&
httpsConnectHostname
==
null
&&
await
CheckAuthorization
(
args
)
==
false
)
{
await
InvokeBeforeResponse
(
args
);
//send the response
//If user requested interception do it
await
clientStreamWriter
.
WriteResponseAsync
(
args
.
WebSession
.
Response
);
await
InvokeBeforeRequest
(
args
);
break
;
}
if
(!
isTransparentEndPoint
)
var
response
=
args
.
WebSession
.
Response
;
{
PrepareRequestHeaders
(
args
.
WebSession
.
Request
.
Headers
);
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
Request
.
RequestUri
.
Authority
;
}
//if win auth is enabled
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
//we need a cache of request body
{
//so that we can send it after authentication in WinAuthHandler.cs
await
HandleHttpSessionResponse
(
args
);
if
(
isWindowsAuthenticationEnabledAndSupported
&&
args
.
WebSession
.
Request
.
HasBody
)
{
await
args
.
GetRequestBody
();
}
//If user requested interception do it
if
(!
response
.
KeepAlive
)
await
InvokeBeforeRequest
(
args
);
{
break
;
}
var
response
=
args
.
WebSession
.
Response
;
continue
;
}
if
(
args
.
WebSession
.
Request
.
CancelRequest
)
//create a new connection if hostname/upstream end point changes
{
if
(
connection
!=
null
await
HandleHttpSessionResponse
(
args
);
&&
(!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
)
||
(
args
.
WebSession
.
UpStreamEndPoint
!=
null
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
{
connection
.
Dispose
();
connection
=
null
;
}
if
(
!
response
.
KeepAlive
)
if
(
connection
==
null
)
{
{
break
;
connection
=
await
GetServerConnection
(
args
,
false
)
;
}
}
continue
;
//if upgrading to websocket then relay the requet without reading the contents
}
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
//prepare the prefix content
var
requestHeaders
=
args
.
WebSession
.
Request
.
Headers
;
await
connection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
);
await
connection
.
StreamWriter
.
WriteHeadersAsync
(
requestHeaders
);
string
httpStatus
=
await
connection
.
StreamReader
.
ReadLineAsync
();
//create a new connection if hostname/upstream end point changes
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
out
int
responseStatusCode
,
if
(
connection
!=
null
out
string
responseStatusDescription
);
&&
(!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
Request
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
)
response
.
HttpVersion
=
responseVersion
;
||
(
args
.
WebSession
.
UpStreamEndPoint
!=
null
response
.
StatusCode
=
responseStatusCode
;
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
response
.
StatusDescription
=
responseStatusDescription
;
{
connection
.
Dispose
();
connection
=
null
;
}
if
(
connection
==
null
)
await
HeaderParser
.
ReadHeaders
(
connection
.
StreamReader
,
response
.
Headers
);
{
connection
=
await
GetServerConnection
(
args
,
false
);
}
//if upgrading to websocket then relay the requet without reading the contents
if
(!
args
.
IsTransparent
)
if
(
args
.
WebSession
.
Request
.
UpgradeToWebSocket
)
{
{
await
clientStreamWriter
.
WriteResponseAsync
(
response
);
//prepare the prefix content
}
var
requestHeaders
=
args
.
WebSession
.
Request
.
Headers
;
await
connection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
);
await
connection
.
StreamWriter
.
WriteHeadersAsync
(
requestHeaders
);
string
httpStatus
=
await
connection
.
StreamReader
.
ReadLineAsync
();
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
out
int
responseStatusCode
,
out
string
responseStatusDescription
);
//If user requested call back then do it
response
.
HttpVersion
=
responseVersion
;
if
(!
args
.
WebSession
.
Response
.
Locked
)
response
.
StatusCode
=
responseStatusCode
;
{
response
.
StatusDescription
=
responseStatusDescription
;
await
InvokeBeforeResponse
(
args
);
}
await
HeaderParser
.
ReadHeaders
(
connection
.
StreamReader
,
response
.
Headers
);
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
BufferSize
,
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
ExceptionFunc
);
if
(!
args
.
IsTransparent
)
break
;
{
await
clientStreamWriter
.
WriteResponseAsync
(
response
);
}
}
//If user requested call back then do it
//construct the web request that we are going to issue on behalf of the client.
if
(!
args
.
WebSession
.
Response
.
ResponseLocked
)
await
HandleHttpSessionRequestInternal
(
connection
,
args
);
//if connection is closing exit
if
(!
response
.
KeepAlive
)
{
{
await
InvokeBeforeResponse
(
args
)
;
break
;
}
}
await
TcpHelper
.
SendRaw
(
clientStream
,
connection
.
Stream
,
BufferSize
,
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataSent
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
ExceptionFunc
);
break
;
}
}
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
//construct the web request that we are going to issue on behalf of the client.
await
HandleHttpSessionRequestInternal
(
connection
,
args
);
//if connection is closing exit
if
(!
response
.
KeepAlive
)
{
{
break
;
throw
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
)
;
}
}
}
}
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
catch
(
Exception
e
)
{
{
throw
new
ProxyHttpException
(
"Error occured whilst handling session request"
,
e
,
args
);
args
.
Exception
=
e
;
throw
;
}
}
finally
finally
{
{
await
InvokeAfterResponse
(
args
);
args
.
Dispose
();
args
.
Dispose
();
}
}
}
}
...
@@ -481,7 +491,7 @@ namespace Titanium.Web.Proxy
...
@@ -481,7 +491,7 @@ namespace Titanium.Web.Proxy
try
try
{
{
var
request
=
args
.
WebSession
.
Request
;
var
request
=
args
.
WebSession
.
Request
;
request
.
Request
Locked
=
true
;
request
.
Locked
=
true
;
//if expect continue is enabled then send the headers first
//if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue
//and see if server would return 100 conitinue
...
@@ -521,17 +531,25 @@ namespace Titanium.Web.Proxy
...
@@ -521,17 +531,25 @@ namespace Titanium.Web.Proxy
//If request was modified by user
//If request was modified by user
if
(
request
.
IsBodyRead
)
if
(
request
.
IsBodyRead
)
{
{
if
(
request
.
ContentEncoding
!=
null
)
bool
isChunked
=
request
.
IsChunked
;
{
string
contentEncoding
=
request
.
ContentEncoding
;
request
.
Body
=
await
GetCompressedResponseBody
(
request
.
ContentEncoding
,
request
.
Body
);
}
var
body
=
request
.
Body
;
var
body
=
request
.
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
//chunked send is not supported as of now
if
(
isChunked
==
false
)
request
.
ContentLength
=
body
.
Length
;
{
request
.
ContentLength
=
body
.
Length
;
}
else
{
request
.
ContentLength
=
-
1
;
}
}
await
args
.
WebSession
.
ServerConnection
.
StreamWriter
.
Write
Async
(
body
);
await
args
.
WebSession
.
ServerConnection
.
StreamWriter
.
Write
BodyAsync
(
body
,
isChunked
);
}
}
else
else
{
{
...
@@ -541,7 +559,7 @@ namespace Titanium.Web.Proxy
...
@@ -541,7 +559,7 @@ namespace Titanium.Web.Proxy
if
(
request
.
HasBody
)
if
(
request
.
HasBody
)
{
{
HttpWriter
writer
=
args
.
WebSession
.
ServerConnection
.
StreamWriter
;
HttpWriter
writer
=
args
.
WebSession
.
ServerConnection
.
StreamWriter
;
await
args
.
CopyRequestBodyAsync
(
writer
,
fals
e
);
await
args
.
CopyRequestBodyAsync
(
writer
,
TransformationMode
.
Non
e
);
}
}
}
}
}
}
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
5e1841ff
using
System
;
using
System
;
using
System.IO
;
using
System.IO.Compression
;
using
System.Net
;
using
System.Net
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.Compression
;
...
@@ -36,7 +38,7 @@ namespace Titanium.Web.Proxy
...
@@ -36,7 +38,7 @@ namespace Titanium.Web.Proxy
args
.
ReRequest
=
false
;
args
.
ReRequest
=
false
;
//if user requested call back then do it
//if user requested call back then do it
if
(!
response
.
Response
Locked
)
if
(!
response
.
Locked
)
{
{
await
InvokeBeforeResponse
(
args
);
await
InvokeBeforeResponse
(
args
);
}
}
...
@@ -51,7 +53,7 @@ namespace Titanium.Web.Proxy
...
@@ -51,7 +53,7 @@ namespace Titanium.Web.Proxy
return
;
return
;
}
}
response
.
Response
Locked
=
true
;
response
.
Locked
=
true
;
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
...
@@ -80,22 +82,23 @@ namespace Titanium.Web.Proxy
...
@@ -80,22 +82,23 @@ namespace Titanium.Web.Proxy
bool
isChunked
=
response
.
IsChunked
;
bool
isChunked
=
response
.
IsChunked
;
string
contentEncoding
=
response
.
ContentEncoding
;
string
contentEncoding
=
response
.
ContentEncoding
;
if
(
contentEncoding
!=
null
)
var
body
=
response
.
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
{
response
.
Body
=
await
GetCompressedResponseBody
(
contentEncoding
,
response
.
B
ody
);
body
=
GetCompressedBody
(
contentEncoding
,
b
ody
);
if
(
isChunked
==
false
)
if
(
isChunked
==
false
)
{
{
response
.
ContentLength
=
response
.
B
ody
.
Length
;
response
.
ContentLength
=
b
ody
.
Length
;
}
}
else
else
{
{
response
.
ContentLength
=
-
1
;
response
.
ContentLength
=
-
1
;
}
}
}
}
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
);
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
);
await
clientStreamWriter
.
WriteBodyAsync
(
response
.
B
ody
,
isChunked
);
await
clientStreamWriter
.
WriteBodyAsync
(
b
ody
,
isChunked
);
}
}
else
else
{
{
...
@@ -104,7 +107,7 @@ namespace Titanium.Web.Proxy
...
@@ -104,7 +107,7 @@ namespace Titanium.Web.Proxy
//Write body if exists
//Write body if exists
if
(
response
.
HasBody
)
if
(
response
.
HasBody
)
{
{
await
args
.
CopyResponseBodyAsync
(
clientStreamWriter
,
fals
e
);
await
args
.
CopyResponseBodyAsync
(
clientStreamWriter
,
TransformationMode
.
Non
e
);
}
}
}
}
}
}
...
@@ -115,15 +118,23 @@ namespace Titanium.Web.Proxy
...
@@ -115,15 +118,23 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// <summary>
/// get the compressed
response body from give response
bytes
/// get the compressed
body from given
bytes
/// </summary>
/// </summary>
/// <param name="encodingType"></param>
/// <param name="encodingType"></param>
/// <param name="
responseBodyStream
"></param>
/// <param name="
body
"></param>
/// <returns></returns>
/// <returns></returns>
private
async
Task
<
byte
[
]>
GetCompressedResponseBody
(
string
encodingType
,
byte
[]
responseBodyStream
)
private
byte
[]
GetCompressedBody
(
string
encodingType
,
byte
[]
body
)
{
{
var
compressor
=
CompressionFactory
.
GetCompression
(
encodingType
);
var
compressor
=
CompressionFactory
.
GetCompression
(
encodingType
);
return
await
compressor
.
Compress
(
responseBodyStream
);
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
compressor
.
GetStream
(
ms
))
{
zip
.
Write
(
body
,
0
,
body
.
Length
);
}
return
ms
.
ToArray
();
}
}
}
...
@@ -134,5 +145,13 @@ namespace Titanium.Web.Proxy
...
@@ -134,5 +145,13 @@ namespace Titanium.Web.Proxy
await
BeforeResponse
.
InvokeAsync
(
this
,
args
,
ExceptionFunc
);
await
BeforeResponse
.
InvokeAsync
(
this
,
args
,
ExceptionFunc
);
}
}
}
}
private
async
Task
InvokeAfterResponse
(
SessionEventArgs
args
)
{
if
(
AfterResponse
!=
null
)
{
await
AfterResponse
.
InvokeAsync
(
this
,
args
,
ExceptionFunc
);
}
}
}
}
}
}
Titanium.Web.Proxy/Titanium.Web.Proxy.csproj
View file @
5e1841ff
...
@@ -13,7 +13,7 @@
...
@@ -13,7 +13,7 @@
<ItemGroup>
<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.4" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.4" />
<PackageReference Include="StreamExtended" Version="1.0.1
38
-beta" />
<PackageReference Include="StreamExtended" Version="1.0.1
41
-beta" />
</ItemGroup>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
...
...
Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec
View file @
5e1841ff
...
@@ -14,7 +14,7 @@
...
@@ -14,7 +14,7 @@
<copyright>
Copyright
©
Titanium. All rights reserved.
</copyright>
<copyright>
Copyright
©
Titanium. All rights reserved.
</copyright>
<tags></tags>
<tags></tags>
<dependencies>
<dependencies>
<dependency
id=
"StreamExtended"
version=
"1.0.1
38
-beta"
/>
<dependency
id=
"StreamExtended"
version=
"1.0.1
41
-beta"
/>
<dependency
id=
"Portable.BouncyCastle"
version=
"1.8.1.4"
/>
<dependency
id=
"Portable.BouncyCastle"
version=
"1.8.1.4"
/>
</dependencies>
</dependencies>
</metadata>
</metadata>
...
...
Titanium.Web.Proxy/packages.config
View file @
5e1841ff
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
packages
>
<
packages
>
<
package
id
=
"Portable.BouncyCastle"
version
=
"1.8.1.4"
targetFramework
=
"net45"
/>
<
package
id
=
"Portable.BouncyCastle"
version
=
"1.8.1.4"
targetFramework
=
"net45"
/>
<
package
id
=
"StreamExtended"
version
=
"1.0.1
38
-beta"
targetFramework
=
"net45"
/>
<
package
id
=
"StreamExtended"
version
=
"1.0.1
41
-beta"
targetFramework
=
"net45"
/>
</
packages
>
</
packages
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment