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
a007c1c0
Unverified
Commit
a007c1c0
authored
Mar 28, 2018
by
honfika
Committed by
GitHub
Mar 28, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #395 from justcoding121/develop
merge to beta
parents
7eb8f297
ef38da77
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
273 additions
and
164 deletions
+273
-164
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+77
-60
TunnelConnectEventArgs.cs
Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
+1
-2
HttpResponseWriter.cs
Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs
+1
-1
HttpWriter.cs
Titanium.Web.Proxy/Helpers/HttpWriter.cs
+20
-6
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+4
-4
Request.cs
Titanium.Web.Proxy/Http/Request.cs
+6
-1
RequestResponseBase.cs
Titanium.Web.Proxy/Http/RequestResponseBase.cs
+75
-6
Response.cs
Titanium.Web.Proxy/Http/Response.cs
+23
-1
OkResponse.cs
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
+8
-0
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+32
-37
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+26
-46
No files found.
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
a007c1c0
...
@@ -107,15 +107,18 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -107,15 +107,18 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// <summary>
/// Constructor to initialize the proxy
/// Constructor to initialize the proxy
/// </summary>
/// </summary>
internal
SessionEventArgs
(
int
bufferSize
,
internal
SessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
ExceptionHandler
exceptionFunc
)
ProxyEndPoint
endPoint
,
:
this
(
bufferSize
,
endPoint
,
exceptionFunc
,
null
)
ExceptionHandler
exceptionFunc
)
{
}
protected
SessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
ExceptionHandler
exceptionFunc
,
Request
request
)
{
{
this
.
bufferSize
=
bufferSize
;
this
.
bufferSize
=
bufferSize
;
this
.
exceptionFunc
=
exceptionFunc
;
this
.
exceptionFunc
=
exceptionFunc
;
ProxyClient
=
new
ProxyClient
();
ProxyClient
=
new
ProxyClient
();
WebSession
=
new
HttpWebClient
(
bufferSize
);
WebSession
=
new
HttpWebClient
(
bufferSize
,
request
);
LocalEndPoint
=
endPoint
;
LocalEndPoint
=
endPoint
;
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
WebSession
.
ProcessId
=
new
Lazy
<
int
>(()
=>
...
@@ -138,6 +141,21 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -138,6 +141,21 @@ namespace Titanium.Web.Proxy.EventArguments
});
});
}
}
private
CustomBufferedStream
GetStream
(
bool
isRequest
)
{
return
isRequest
?
ProxyClient
.
ClientStream
:
WebSession
.
ServerConnection
.
Stream
;
}
private
CustomBinaryReader
GetStreamReader
(
bool
isRequest
)
{
return
isRequest
?
ProxyClient
.
ClientStreamReader
:
WebSession
.
ServerConnection
.
StreamReader
;
}
private
HttpWriter
GetStreamWriter
(
bool
isRequest
)
{
return
isRequest
?
(
HttpWriter
)
ProxyClient
.
ClientStreamWriter
:
WebSession
.
ServerConnection
.
StreamWriter
;
}
/// <summary>
/// <summary>
/// Read request body content as bytes[] for current session
/// Read request body content as bytes[] for current session
/// </summary>
/// </summary>
...
@@ -150,7 +168,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -150,7 +168,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
,
true
);
var
body
=
await
ReadBodyAsync
(
true
);
request
.
Body
=
body
;
request
.
Body
=
body
;
//Now set the flag to true
//Now set the flag to true
...
@@ -165,8 +183,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -165,8 +183,8 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// </summary>
internal
async
Task
ClearResponse
()
internal
async
Task
ClearResponse
()
{
{
//s
iphon out the body
//s
yphon out the response body from server
await
ReadResponseBodyAsync
(
);
await
SyphonOutBodyAsync
(
false
);
WebSession
.
Response
=
new
Response
();
WebSession
.
Response
=
new
Response
();
}
}
...
@@ -225,7 +243,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -225,7 +243,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
,
false
);
var
body
=
await
ReadBodyAsync
(
false
);
response
.
Body
=
body
;
response
.
Body
=
body
;
//Now set the flag to true
//Now set the flag to true
...
@@ -235,11 +253,12 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -235,11 +253,12 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
}
}
private
async
Task
<
byte
[
]>
ReadBodyAsync
(
CustomBinaryReader
reader
,
bool
isRequest
)
private
async
Task
<
byte
[
]>
ReadBodyAsync
(
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
,
TransformationMode
.
Uncompress
);
await
CopyRequestBodyAsync
(
writer
,
TransformationMode
.
Uncompress
);
...
@@ -253,21 +272,35 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -253,21 +272,35 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
}
}
internal
async
Task
SyphonOutBodyAsync
(
bool
isRequest
)
{
var
requestResponse
=
isRequest
?
(
RequestResponseBase
)
WebSession
.
Request
:
WebSession
.
Response
;
if
(
requestResponse
.
IsBodyRead
||
!
requestResponse
.
OriginalHasBody
)
{
return
;
}
using
(
var
bodyStream
=
new
MemoryStream
())
{
var
writer
=
new
HttpWriter
(
bodyStream
,
bufferSize
);
await
CopyBodyAsync
(
isRequest
,
writer
,
TransformationMode
.
None
,
null
);
}
}
/// <summary>
/// <summary>
/// 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
,
TransformationMode
transformation
)
internal
async
Task
CopyRequestBodyAsync
(
HttpWriter
writer
,
TransformationMode
transformation
)
{
{
// End the operation
var
request
=
WebSession
.
Request
;
var
request
=
WebSession
.
Request
;
var
reader
=
ProxyClient
.
ClientStreamReader
;
long
contentLength
=
request
.
ContentLength
;
long
contentLength
=
request
.
ContentLength
;
//send the request body bytes to server
//send the request body bytes to server
if
(
contentLength
>
0
&&
hasMulipartEventSubscribers
&&
request
.
IsMultipartFormData
)
if
(
contentLength
>
0
&&
hasMulipartEventSubscribers
&&
request
.
IsMultipartFormData
)
{
{
var
reader
=
GetStreamReader
(
true
);
string
boundary
=
HttpHelper
.
GetBoundaryFromContentType
(
request
.
ContentType
);
string
boundary
=
HttpHelper
.
GetBoundaryFromContentType
(
request
.
ContentType
);
using
(
var
copyStream
=
new
CopyStream
(
reader
,
writer
,
bufferSize
))
using
(
var
copyStream
=
new
CopyStream
(
reader
,
writer
,
bufferSize
))
...
@@ -294,21 +327,22 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -294,21 +327,22 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
else
else
{
{
await
CopyBodyAsync
(
ProxyClient
.
ClientStream
,
reader
,
writer
,
request
,
transformation
,
OnDataSent
);
await
CopyBodyAsync
(
true
,
writer
,
transformation
,
OnDataSent
);
}
}
}
}
internal
async
Task
CopyResponseBodyAsync
(
HttpWriter
writer
,
TransformationMode
transformation
)
internal
async
Task
CopyResponseBodyAsync
(
HttpWriter
writer
,
TransformationMode
transformation
)
{
{
var
response
=
WebSession
.
Response
;
await
CopyBodyAsync
(
false
,
writer
,
transformation
,
OnDataReceived
);
var
reader
=
WebSession
.
ServerConnection
.
StreamReader
;
await
CopyBodyAsync
(
WebSession
.
ServerConnection
.
Stream
,
reader
,
writer
,
response
,
transformation
,
OnDataReceived
);
}
}
private
async
Task
CopyBodyAsync
(
CustomBufferedStream
stream
,
CustomBinaryReader
reader
,
HttpWriter
writer
,
private
async
Task
CopyBodyAsync
(
bool
isRequest
,
HttpWriter
writer
,
TransformationMode
transformation
,
Action
<
byte
[],
int
,
int
>
onCopy
)
RequestResponseBase
requestResponse
,
TransformationMode
transformation
,
Action
<
byte
[],
int
,
int
>
onCopy
)
{
{
var
stream
=
GetStream
(
isRequest
);
var
reader
=
GetStreamReader
(
isRequest
);
var
requestResponse
=
isRequest
?
(
RequestResponseBase
)
WebSession
.
Request
:
WebSession
.
Response
;
bool
isChunked
=
requestResponse
.
IsChunked
;
bool
isChunked
=
requestResponse
.
IsChunked
;
long
contentLength
=
requestResponse
.
ContentLength
;
long
contentLength
=
requestResponse
.
ContentLength
;
if
(
transformation
==
TransformationMode
.
None
)
if
(
transformation
==
TransformationMode
.
None
)
...
@@ -440,7 +474,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -440,7 +474,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Sets the request body
/// Sets the request body
/// </summary>
/// </summary>
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetRequestBody
(
byte
[]
body
)
public
void
SetRequestBody
(
byte
[]
body
)
{
{
var
request
=
WebSession
.
Request
;
var
request
=
WebSession
.
Request
;
if
(
request
.
Locked
)
if
(
request
.
Locked
)
...
@@ -448,34 +482,21 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -448,34 +482,21 @@ namespace Titanium.Web.Proxy.EventArguments
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
if
(!
request
.
IsBodyRead
)
{
await
ReadRequestBodyAsync
();
}
request
.
Body
=
body
;
request
.
Body
=
body
;
request
.
UpdateContentLength
();
}
}
/// <summary>
/// <summary>
/// Sets the body with the specified string
/// Sets the body with the specified string
/// </summary>
/// </summary>
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetRequestBodyString
(
string
body
)
public
void
SetRequestBodyString
(
string
body
)
{
{
if
(
WebSession
.
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."
);
}
}
//syphon out the request body from client before setting the new body
SetRequestBody
(
WebSession
.
Request
.
Encoding
.
GetBytes
(
body
));
if
(!
WebSession
.
Request
.
IsBodyRead
)
{
await
ReadRequestBodyAsync
();
}
await
SetRequestBody
(
WebSession
.
Request
.
Encoding
.
GetBytes
(
body
));
}
}
/// <summary>
/// <summary>
...
@@ -510,7 +531,7 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -510,7 +531,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Set the response body bytes
/// Set the response body bytes
/// </summary>
/// </summary>
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetResponseBody
(
byte
[]
body
)
public
void
SetResponseBody
(
byte
[]
body
)
{
{
if
(!
WebSession
.
Request
.
Locked
)
if
(!
WebSession
.
Request
.
Locked
)
{
{
...
@@ -518,39 +539,23 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -518,39 +539,23 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
var
response
=
WebSession
.
Response
;
var
response
=
WebSession
.
Response
;
//syphon out the response body from server before setting the new body
if
(
response
.
Body
==
null
)
{
await
GetResponseBody
();
}
response
.
Body
=
body
;
response
.
Body
=
body
;
//If there is a content length header update it
response
.
UpdateContentLength
();
}
}
/// <summary>
/// <summary>
/// Replace the response body with the specified string
/// Replace the response body with the specified string
/// </summary>
/// </summary>
/// <param name="body"></param>
/// <param name="body"></param>
public
async
Task
SetResponseBodyString
(
string
body
)
public
void
SetResponseBodyString
(
string
body
)
{
{
if
(!
WebSession
.
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."
);
}
}
//syphon out the response body from server before setting the new body
if
(!
WebSession
.
Response
.
IsBodyRead
)
{
await
GetResponseBody
();
}
var
bodyBytes
=
WebSession
.
Response
.
Encoding
.
GetBytes
(
body
);
var
bodyBytes
=
WebSession
.
Response
.
Encoding
.
GetBytes
(
body
);
await
SetResponseBody
(
bodyBytes
);
SetResponseBody
(
bodyBytes
);
}
}
/// <summary>
/// <summary>
...
@@ -651,17 +656,29 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -651,17 +656,29 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
if
(
WebSession
.
Request
.
Locked
)
if
(
WebSession
.
Request
.
Locked
)
{
{
throw
new
Exception
(
"You cannot call this function after request is made to server."
);
if
(
WebSession
.
Response
.
Locked
)
}
{
throw
new
Exception
(
"You cannot call this function after response is sent to the client."
);
}
WebSession
.
Request
.
Locked
=
true
;
response
.
Locked
=
true
;
response
.
TerminateResponse
=
WebSession
.
Response
.
TerminateResponse
;
WebSession
.
Response
=
response
;
}
else
{
WebSession
.
Request
.
Locked
=
true
;
response
.
Locked
=
true
;
response
.
Locked
=
true
;
response
.
IsBodyRead
=
tru
e
;
WebSession
.
Response
=
respons
e
;
WebSession
.
Response
=
response
;
WebSession
.
Request
.
CancelRequest
=
true
;
}
}
WebSession
.
Request
.
CancelRequest
=
true
;
public
void
TerminateServerConnection
()
{
WebSession
.
Response
.
TerminateResponse
=
true
;
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
View file @
a007c1c0
...
@@ -11,9 +11,8 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -11,9 +11,8 @@ namespace Titanium.Web.Proxy.EventArguments
public
bool
IsHttpsConnect
{
get
;
internal
set
;
}
public
bool
IsHttpsConnect
{
get
;
internal
set
;
}
internal
TunnelConnectSessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
ConnectRequest
connectRequest
,
ExceptionHandler
exceptionFunc
)
internal
TunnelConnectSessionEventArgs
(
int
bufferSize
,
ProxyEndPoint
endPoint
,
ConnectRequest
connectRequest
,
ExceptionHandler
exceptionFunc
)
:
base
(
bufferSize
,
endPoint
,
exceptionFunc
)
:
base
(
bufferSize
,
endPoint
,
exceptionFunc
,
connectRequest
)
{
{
WebSession
.
Request
=
connectRequest
;
}
}
}
}
}
}
Titanium.Web.Proxy/Helpers/HttpResponseWriter.cs
View file @
a007c1c0
...
@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -20,7 +20,7 @@ namespace Titanium.Web.Proxy.Helpers
public
async
Task
WriteResponseAsync
(
Response
response
,
bool
flush
=
true
)
public
async
Task
WriteResponseAsync
(
Response
response
,
bool
flush
=
true
)
{
{
await
WriteResponseStatusAsync
(
response
.
HttpVersion
,
response
.
StatusCode
,
response
.
StatusDescription
);
await
WriteResponseStatusAsync
(
response
.
HttpVersion
,
response
.
StatusCode
,
response
.
StatusDescription
);
await
Write
HeadersAsync
(
response
.
Headers
,
flush
);
await
Write
Async
(
response
,
flush
);
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Helpers/HttpWriter.cs
View file @
a007c1c0
...
@@ -5,7 +5,7 @@ using System.Text;
...
@@ -5,7 +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.
Compression
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Shared
;
using
Titanium.Web.Proxy.Shared
;
...
@@ -94,12 +94,9 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -94,12 +94,9 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns>
/// <returns></returns>
public
async
Task
WriteHeadersAsync
(
HeaderCollection
headers
,
bool
flush
=
true
)
public
async
Task
WriteHeadersAsync
(
HeaderCollection
headers
,
bool
flush
=
true
)
{
{
if
(
headers
!=
null
)
foreach
(
var
header
in
headers
)
{
{
foreach
(
var
header
in
headers
)
await
header
.
WriteToStreamAsync
(
this
);
{
await
header
.
WriteToStreamAsync
(
this
);
}
}
}
await
WriteLineAsync
();
await
WriteLineAsync
();
...
@@ -265,5 +262,22 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -265,5 +262,22 @@ namespace Titanium.Web.Proxy.Helpers
onCopy
?.
Invoke
(
buffer
,
0
,
bytesRead
);
onCopy
?.
Invoke
(
buffer
,
0
,
bytesRead
);
}
}
}
}
/// <summary>
/// Writes the request/response headers and body.
/// </summary>
/// <param name="requestResponse"></param>
/// <param name="flush"></param>
/// <returns></returns>
protected
async
Task
WriteAsync
(
RequestResponseBase
requestResponse
,
bool
flush
=
true
)
{
var
body
=
requestResponse
.
CompressBodyAndUpdateContentLength
();
await
WriteHeadersAsync
(
requestResponse
.
Headers
,
flush
);
if
(
body
!=
null
)
{
await
WriteBodyAsync
(
body
,
requestResponse
.
IsChunked
);
}
}
}
}
}
}
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
a007c1c0
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Web Request.
/// Web Request.
/// </summary>
/// </summary>
public
Request
Request
{
get
;
internal
set
;
}
public
Request
Request
{
get
;
}
/// <summary>
/// <summary>
/// Web Response.
/// Web Response.
...
@@ -56,13 +56,13 @@ namespace Titanium.Web.Proxy.Http
...
@@ -56,13 +56,13 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
public
bool
IsHttps
=>
Request
.
IsHttps
;
public
bool
IsHttps
=>
Request
.
IsHttps
;
internal
HttpWebClient
(
int
bufferSize
)
internal
HttpWebClient
(
int
bufferSize
,
Request
request
=
null
,
Response
response
=
null
)
{
{
this
.
bufferSize
=
bufferSize
;
this
.
bufferSize
=
bufferSize
;
RequestId
=
Guid
.
NewGuid
();
RequestId
=
Guid
.
NewGuid
();
Request
=
new
Request
();
Request
=
request
??
new
Request
();
Response
=
new
Response
();
Response
=
response
??
new
Response
();
}
}
/// <summary>
/// <summary>
...
...
Titanium.Web.Proxy/Http/Request.cs
View file @
a007c1c0
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Has request body?
/// Has request body?
/// </summary>
/// </summary>
public
bool
HasBody
public
override
bool
HasBody
{
{
get
get
{
{
...
@@ -102,6 +102,11 @@ namespace Titanium.Web.Proxy.Http
...
@@ -102,6 +102,11 @@ namespace Titanium.Web.Proxy.Http
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
{
{
if
(
BodyInternal
!=
null
)
{
return
;
}
//GET request don't have a request body to read
//GET request don't have a request body to read
if
(!
HasBody
)
if
(!
HasBody
)
{
{
...
...
Titanium.Web.Proxy/Http/RequestResponseBase.cs
View file @
a007c1c0
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.ComponentModel
;
using
System.ComponentModel
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Text
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Extensions
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Models
;
using
Titanium.Web.Proxy.Models
;
...
@@ -15,7 +16,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -15,7 +16,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Cached body content as byte array
/// Cached body content as byte array
/// </summary>
/// </summary>
pr
ivate
byte
[]
body
;
pr
otected
byte
[]
BodyInternal
;
/// <summary>
/// <summary>
/// Cached body as string
/// Cached body as string
...
@@ -126,16 +127,84 @@ namespace Titanium.Web.Proxy.Http
...
@@ -126,16 +127,84 @@ namespace Titanium.Web.Proxy.Http
get
get
{
{
EnsureBodyAvailable
();
EnsureBodyAvailable
();
return
body
;
return
BodyInternal
;
}
}
internal
set
internal
set
{
{
body
=
value
;
BodyInternal
=
value
;
bodyString
=
null
;
bodyString
=
null
;
//If there is a content length header update it
UpdateContentLength
();
}
}
}
}
/// <summary>
/// Has the request/response body?
/// </summary>
public
abstract
bool
HasBody
{
get
;
}
/// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters
/// </summary>
internal
bool
OriginalHasBody
;
internal
abstract
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
);
internal
abstract
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
);
/// <summary>
/// get the compressed body from given bytes
/// </summary>
/// <param name="encodingType"></param>
/// <param name="body"></param>
/// <returns></returns>
internal
byte
[]
GetCompressedBody
(
string
encodingType
,
byte
[]
body
)
{
var
compressor
=
CompressionFactory
.
GetCompression
(
encodingType
);
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
compressor
.
GetStream
(
ms
))
{
zip
.
Write
(
body
,
0
,
body
.
Length
);
}
return
ms
.
ToArray
();
}
}
internal
byte
[]
CompressBodyAndUpdateContentLength
()
{
if
(!
IsBodyRead
&&
BodyInternal
==
null
)
{
return
null
;
}
bool
isChunked
=
IsChunked
;
string
contentEncoding
=
ContentEncoding
;
if
(
HasBody
)
{
var
body
=
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
if
(
isChunked
==
false
)
{
ContentLength
=
body
.
Length
;
}
else
{
ContentLength
=
-
1
;
}
}
return
body
;
}
ContentLength
=
0
;
return
null
;
}
/// <summary>
/// <summary>
/// Body as string
/// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// Use the encoding specified to decode the byte[] data to string
...
@@ -155,7 +224,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -155,7 +224,7 @@ namespace Titanium.Web.Proxy.Http
internal
void
UpdateContentLength
()
internal
void
UpdateContentLength
()
{
{
ContentLength
=
IsChunked
?
-
1
:
body
.
Length
;
ContentLength
=
IsChunked
?
-
1
:
BodyInternal
?.
Length
??
0
;
}
}
/// <summary>
/// <summary>
...
@@ -165,7 +234,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -165,7 +234,7 @@ namespace Titanium.Web.Proxy.Http
{
{
if
(!
KeepBody
)
if
(!
KeepBody
)
{
{
body
=
null
;
BodyInternal
=
null
;
bodyString
=
null
;
bodyString
=
null
;
}
}
}
}
...
...
Titanium.Web.Proxy/Http/Response.cs
View file @
a007c1c0
...
@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// <summary>
/// Has response body?
/// Has response body?
/// </summary>
/// </summary>
public
bool
HasBody
public
override
bool
HasBody
{
{
get
get
{
{
...
@@ -77,8 +77,15 @@ namespace Titanium.Web.Proxy.Http
...
@@ -77,8 +77,15 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
internal
bool
TerminateResponse
{
get
;
set
;
}
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
internal
override
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
)
{
{
if
(
BodyInternal
!=
null
)
{
return
;
}
if
(!
IsBodyRead
&&
throwWhenNotReadYet
)
if
(!
IsBodyRead
&&
throwWhenNotReadYet
)
{
{
throw
new
Exception
(
"Response body is not read yet. "
+
throw
new
Exception
(
"Response body is not read yet. "
+
...
@@ -121,6 +128,21 @@ namespace Titanium.Web.Proxy.Http
...
@@ -121,6 +128,21 @@ namespace Titanium.Web.Proxy.Http
}
}
}
}
/// <summary>
/// Constructor.
/// </summary>
public
Response
()
{
}
/// <summary>
/// Constructor.
/// </summary>
public
Response
(
byte
[]
body
)
{
Body
=
body
;
}
internal
static
string
CreateResponseLine
(
Version
version
,
int
statusCode
,
string
statusDescription
)
internal
static
string
CreateResponseLine
(
Version
version
,
int
statusCode
,
string
statusDescription
)
{
{
return
$"HTTP/
{
version
.
Major
}
.
{
version
.
Minor
}
{
statusCode
}
{
statusDescription
}
"
;
return
$"HTTP/
{
version
.
Major
}
.
{
version
.
Minor
}
{
statusCode
}
{
statusDescription
}
"
;
...
...
Titanium.Web.Proxy/Http/Responses/OkResponse.cs
View file @
a007c1c0
...
@@ -15,5 +15,13 @@ namespace Titanium.Web.Proxy.Http.Responses
...
@@ -15,5 +15,13 @@ namespace Titanium.Web.Proxy.Http.Responses
StatusCode
=
(
int
)
HttpStatusCode
.
OK
;
StatusCode
=
(
int
)
HttpStatusCode
.
OK
;
StatusDescription
=
"OK"
;
StatusDescription
=
"OK"
;
}
}
/// <summary>
/// Constructor.
/// </summary>
public
OkResponse
(
byte
[]
body
)
:
this
()
{
Body
=
body
;
}
}
}
}
}
Titanium.Web.Proxy/RequestHandler.cs
View file @
a007c1c0
...
@@ -46,7 +46,6 @@ namespace Titanium.Web.Proxy
...
@@ -46,7 +46,6 @@ namespace Titanium.Web.Proxy
try
try
{
{
string
connectHostname
=
null
;
string
connectHostname
=
null
;
ConnectRequest
connectRequest
=
null
;
ConnectRequest
connectRequest
=
null
;
//Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
//Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
...
@@ -297,7 +296,7 @@ namespace Titanium.Web.Proxy
...
@@ -297,7 +296,7 @@ namespace Titanium.Web.Proxy
string
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
string
httpCmd
=
await
clientStreamReader
.
ReadLineAsync
();
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
if
(
string
.
IsNullOrEmpty
(
httpCmd
))
{
{
break
;
return
;
}
}
var
args
=
new
SessionEventArgs
(
BufferSize
,
endPoint
,
ExceptionFunc
)
var
args
=
new
SessionEventArgs
(
BufferSize
,
endPoint
,
ExceptionFunc
)
...
@@ -347,11 +346,12 @@ namespace Titanium.Web.Proxy
...
@@ -347,11 +346,12 @@ namespace Titanium.Web.Proxy
}
}
}
}
args
.
WebSession
.
Request
.
RequestUri
=
httpRemoteUri
;
var
request
=
args
.
WebSession
.
Request
;
args
.
WebSession
.
Request
.
OriginalUrl
=
httpUrl
;
request
.
RequestUri
=
httpRemoteUri
;
request
.
OriginalUrl
=
httpUrl
;
args
.
WebSession
.
R
equest
.
Method
=
httpMethod
;
r
equest
.
Method
=
httpMethod
;
args
.
WebSession
.
R
equest
.
HttpVersion
=
version
;
r
equest
.
HttpVersion
=
version
;
args
.
ProxyClient
.
ClientStream
=
clientStream
;
args
.
ProxyClient
.
ClientStream
=
clientStream
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamReader
=
clientStreamReader
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
args
.
ProxyClient
.
ClientStreamWriter
=
clientStreamWriter
;
...
@@ -363,35 +363,40 @@ namespace Titanium.Web.Proxy
...
@@ -363,35 +363,40 @@ namespace Titanium.Web.Proxy
//send the response
//send the response
await
clientStreamWriter
.
WriteResponseAsync
(
args
.
WebSession
.
Response
);
await
clientStreamWriter
.
WriteResponseAsync
(
args
.
WebSession
.
Response
);
break
;
return
;
}
}
if
(!
isTransparentEndPoint
)
if
(!
isTransparentEndPoint
)
{
{
PrepareRequestHeaders
(
args
.
WebSession
.
R
equest
.
Headers
);
PrepareRequestHeaders
(
r
equest
.
Headers
);
args
.
WebSession
.
Request
.
Host
=
args
.
WebSession
.
R
equest
.
RequestUri
.
Authority
;
request
.
Host
=
r
equest
.
RequestUri
.
Authority
;
}
}
//if win auth is enabled
//if win auth is enabled
//we need a cache of request body
//we need a cache of request body
//so that we can send it after authentication in WinAuthHandler.cs
//so that we can send it after authentication in WinAuthHandler.cs
if
(
isWindowsAuthenticationEnabledAndSupported
&&
args
.
WebSession
.
R
equest
.
HasBody
)
if
(
isWindowsAuthenticationEnabledAndSupported
&&
r
equest
.
HasBody
)
{
{
await
args
.
GetRequestBody
();
await
args
.
GetRequestBody
();
}
}
request
.
OriginalHasBody
=
request
.
HasBody
;
//If user requested interception do it
//If user requested interception do it
await
InvokeBeforeRequest
(
args
);
await
InvokeBeforeRequest
(
args
);
var
response
=
args
.
WebSession
.
Response
;
var
response
=
args
.
WebSession
.
Response
;
if
(
args
.
WebSession
.
R
equest
.
CancelRequest
)
if
(
r
equest
.
CancelRequest
)
{
{
//syphon out the request body from client before setting the new body
await
args
.
SyphonOutBodyAsync
(
true
);
await
HandleHttpSessionResponse
(
args
);
await
HandleHttpSessionResponse
(
args
);
if
(!
response
.
KeepAlive
)
if
(!
response
.
KeepAlive
)
{
{
break
;
return
;
}
}
continue
;
continue
;
...
@@ -399,7 +404,7 @@ namespace Titanium.Web.Proxy
...
@@ -399,7 +404,7 @@ namespace Titanium.Web.Proxy
//create a new connection if hostname/upstream end point changes
//create a new connection if hostname/upstream end point changes
if
(
connection
!=
null
if
(
connection
!=
null
&&
(!
connection
.
HostName
.
Equals
(
args
.
WebSession
.
R
equest
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
)
&&
(!
connection
.
HostName
.
Equals
(
r
equest
.
RequestUri
.
Host
,
StringComparison
.
OrdinalIgnoreCase
)
||
(
args
.
WebSession
.
UpStreamEndPoint
!=
null
||
(
args
.
WebSession
.
UpStreamEndPoint
!=
null
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
&&
!
args
.
WebSession
.
UpStreamEndPoint
.
Equals
(
connection
.
UpStreamEndPoint
))))
{
{
...
@@ -413,12 +418,11 @@ namespace Titanium.Web.Proxy
...
@@ -413,12 +418,11 @@ namespace Titanium.Web.Proxy
}
}
//if upgrading to websocket then relay the requet without reading the contents
//if upgrading to websocket then relay the requet without reading the contents
if
(
args
.
WebSession
.
R
equest
.
UpgradeToWebSocket
)
if
(
r
equest
.
UpgradeToWebSocket
)
{
{
//prepare the prefix content
//prepare the prefix content
var
requestHeaders
=
args
.
WebSession
.
Request
.
Headers
;
await
connection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
);
await
connection
.
StreamWriter
.
WriteLineAsync
(
httpCmd
);
await
connection
.
StreamWriter
.
WriteHeadersAsync
(
requestHeaders
);
await
connection
.
StreamWriter
.
WriteHeadersAsync
(
request
.
Headers
);
string
httpStatus
=
await
connection
.
StreamReader
.
ReadLineAsync
();
string
httpStatus
=
await
connection
.
StreamReader
.
ReadLineAsync
();
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
out
int
responseStatusCode
,
Response
.
ParseResponseLine
(
httpStatus
,
out
var
responseVersion
,
out
int
responseStatusCode
,
...
@@ -445,16 +449,22 @@ namespace Titanium.Web.Proxy
...
@@ -445,16 +449,22 @@ namespace Titanium.Web.Proxy
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
(
buffer
,
offset
,
count
)
=>
{
args
.
OnDataReceived
(
buffer
,
offset
,
count
);
},
ExceptionFunc
);
ExceptionFunc
);
break
;
return
;
}
}
//construct the web request that we are going to issue on behalf of the client.
//construct the web request that we are going to issue on behalf of the client.
await
HandleHttpSessionRequestInternal
(
connection
,
args
);
await
HandleHttpSessionRequestInternal
(
connection
,
args
);
if
(
args
.
WebSession
.
ServerConnection
==
null
)
{
//server connection was closed
return
;
}
//if connection is closing exit
//if connection is closing exit
if
(!
response
.
KeepAlive
)
if
(!
response
.
KeepAlive
)
{
{
break
;
return
;
}
}
}
}
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
catch
(
Exception
e
)
when
(!(
e
is
ProxyHttpException
))
...
@@ -493,6 +503,8 @@ namespace Titanium.Web.Proxy
...
@@ -493,6 +503,8 @@ namespace Titanium.Web.Proxy
var
request
=
args
.
WebSession
.
Request
;
var
request
=
args
.
WebSession
.
Request
;
request
.
Locked
=
true
;
request
.
Locked
=
true
;
var
body
=
request
.
CompressBodyAndUpdateContentLength
();
//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
if
(
request
.
ExpectContinue
)
if
(
request
.
ExpectContinue
)
...
@@ -531,25 +543,8 @@ namespace Titanium.Web.Proxy
...
@@ -531,25 +543,8 @@ namespace Titanium.Web.Proxy
//If request was modified by user
//If request was modified by user
if
(
request
.
IsBodyRead
)
if
(
request
.
IsBodyRead
)
{
{
bool
isChunked
=
request
.
IsChunked
;
var
writer
=
args
.
WebSession
.
ServerConnection
.
StreamWriter
;
string
contentEncoding
=
request
.
ContentEncoding
;
await
writer
.
WriteBodyAsync
(
body
,
request
.
IsChunked
);
var
body
=
request
.
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
if
(
isChunked
==
false
)
{
request
.
ContentLength
=
body
.
Length
;
}
else
{
request
.
ContentLength
=
-
1
;
}
}
await
args
.
WebSession
.
ServerConnection
.
StreamWriter
.
WriteBodyAsync
(
body
,
isChunked
);
}
}
else
else
{
{
...
...
Titanium.Web.Proxy/ResponseHandler.cs
View file @
a007c1c0
...
@@ -43,6 +43,29 @@ namespace Titanium.Web.Proxy
...
@@ -43,6 +43,29 @@ namespace Titanium.Web.Proxy
await
InvokeBeforeResponse
(
args
);
await
InvokeBeforeResponse
(
args
);
}
}
// it may changed in the user event
response
=
args
.
WebSession
.
Response
;
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
if
(
response
.
TerminateResponse
||
response
.
Locked
)
{
await
clientStreamWriter
.
WriteResponseAsync
(
response
);
if
(!
response
.
TerminateResponse
)
{
//syphon out the response body from server before setting the new body
await
args
.
SyphonOutBodyAsync
(
false
);
}
else
{
args
.
WebSession
.
ServerConnection
.
Dispose
();
args
.
WebSession
.
ServerConnection
=
null
;
}
return
;
}
//if user requested to send request again
//if user requested to send request again
//likely after making modifications from User Response Handler
//likely after making modifications from User Response Handler
if
(
args
.
ReRequest
)
if
(
args
.
ReRequest
)
...
@@ -55,8 +78,6 @@ namespace Titanium.Web.Proxy
...
@@ -55,8 +78,6 @@ namespace Titanium.Web.Proxy
response
.
Locked
=
true
;
response
.
Locked
=
true
;
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
//Write back to client 100-conitinue response if that's what server returned
//Write back to client 100-conitinue response if that's what server returned
if
(
response
.
Is100Continue
)
if
(
response
.
Is100Continue
)
{
{
...
@@ -69,9 +90,6 @@ namespace Titanium.Web.Proxy
...
@@ -69,9 +90,6 @@ namespace Titanium.Web.Proxy
await
clientStreamWriter
.
WriteLineAsync
();
await
clientStreamWriter
.
WriteLineAsync
();
}
}
//Write back response status to client
await
clientStreamWriter
.
WriteResponseStatusAsync
(
response
.
HttpVersion
,
response
.
StatusCode
,
response
.
StatusDescription
);
if
(!
args
.
IsTransparent
)
if
(!
args
.
IsTransparent
)
{
{
response
.
Headers
.
FixProxyHeaders
();
response
.
Headers
.
FixProxyHeaders
();
...
@@ -79,29 +97,12 @@ namespace Titanium.Web.Proxy
...
@@ -79,29 +97,12 @@ namespace Titanium.Web.Proxy
if
(
response
.
IsBodyRead
)
if
(
response
.
IsBodyRead
)
{
{
bool
isChunked
=
response
.
IsChunked
;
await
clientStreamWriter
.
WriteResponseAsync
(
response
);
string
contentEncoding
=
response
.
ContentEncoding
;
var
body
=
response
.
Body
;
if
(
contentEncoding
!=
null
&&
body
!=
null
)
{
body
=
GetCompressedBody
(
contentEncoding
,
body
);
if
(
isChunked
==
false
)
{
response
.
ContentLength
=
body
.
Length
;
}
else
{
response
.
ContentLength
=
-
1
;
}
}
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
);
await
clientStreamWriter
.
WriteBodyAsync
(
body
,
isChunked
);
}
}
else
else
{
{
//Write back response status to client
await
clientStreamWriter
.
WriteResponseStatusAsync
(
response
.
HttpVersion
,
response
.
StatusCode
,
response
.
StatusDescription
);
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
);
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
);
//Write body if exists
//Write body if exists
...
@@ -117,27 +118,6 @@ namespace Titanium.Web.Proxy
...
@@ -117,27 +118,6 @@ namespace Titanium.Web.Proxy
}
}
}
}
/// <summary>
/// get the compressed body from given bytes
/// </summary>
/// <param name="encodingType"></param>
/// <param name="body"></param>
/// <returns></returns>
private
byte
[]
GetCompressedBody
(
string
encodingType
,
byte
[]
body
)
{
var
compressor
=
CompressionFactory
.
GetCompression
(
encodingType
);
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
compressor
.
GetStream
(
ms
))
{
zip
.
Write
(
body
,
0
,
body
.
Length
);
}
return
ms
.
ToArray
();
}
}
private
async
Task
InvokeBeforeResponse
(
SessionEventArgs
args
)
private
async
Task
InvokeBeforeResponse
(
SessionEventArgs
args
)
{
{
if
(
BeforeResponse
!=
null
)
if
(
BeforeResponse
!=
null
)
...
...
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