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
42a5ee99
Commit
42a5ee99
authored
Apr 27, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
allow to change http/2 body
parent
7330b5c3
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
200 additions
and
72 deletions
+200
-72
MainWindow.xaml.cs
examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
+7
-1
SessionEventArgs.cs
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+14
-0
RequestResponseBase.cs
src/Titanium.Web.Proxy/Http/RequestResponseBase.cs
+11
-0
Http2Helper.cs
src/Titanium.Web.Proxy/Http2/Http2Helper.cs
+168
-70
ResponseHandler.cs
src/Titanium.Web.Proxy/ResponseHandler.cs
+0
-1
No files found.
examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
View file @
42a5ee99
...
@@ -159,6 +159,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -159,6 +159,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf
//{
//{
//}
//}
//if (!e.HttpClient.Request.RequestUri.ToString().Contains("/mail/u/"))
// return;
if
(
e
.
HttpClient
.
Request
.
HasBody
)
if
(
e
.
HttpClient
.
Request
.
HasBody
)
{
{
e
.
HttpClient
.
Request
.
KeepBody
=
true
;
e
.
HttpClient
.
Request
.
KeepBody
=
true
;
...
@@ -177,7 +180,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf
...
@@ -177,7 +180,10 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
}
});
});
e
.
HttpClient
.
Response
.
Headers
.
AddHeader
(
"X-Titanium-Header"
,
"HTTP/2 works"
);
//e.SetResponseBody(Encoding.ASCII.GetBytes("TITANIUMMMM!!!!"));
//if (!e.HttpClient.Request.RequestUri.ToString().Contains("/mail/u/"))
// return;
//e.HttpClient.Response.Headers.AddHeader("X-Titanium-Header", "HTTP/2 works");
//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//{
//{
...
...
src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
42a5ee99
...
@@ -91,6 +91,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -91,6 +91,9 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
if
(
request
.
HttpVersion
==
HttpHeader
.
Version20
)
if
(
request
.
HttpVersion
==
HttpHeader
.
Version20
)
{
{
// do not send to the remote endpoint
request
.
Http2IgnoreBodyFrames
=
true
;
request
.
Http2BodyData
=
new
MemoryStream
();
request
.
Http2BodyData
=
new
MemoryStream
();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
...
@@ -100,6 +103,10 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -100,6 +103,10 @@ namespace Titanium.Web.Proxy.EventArguments
request
.
ReadHttp2BeforeHandlerTaskCompletionSource
.
SetResult
(
true
);
request
.
ReadHttp2BeforeHandlerTaskCompletionSource
.
SetResult
(
true
);
await
tcs
.
Task
;
await
tcs
.
Task
;
// Now set the flag to true
// So that next time we can deliver body from cache
request
.
IsBodyRead
=
true
;
}
}
else
else
{
{
...
@@ -157,6 +164,9 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -157,6 +164,9 @@ namespace Titanium.Web.Proxy.EventArguments
{
{
if
(
response
.
HttpVersion
==
HttpHeader
.
Version20
)
if
(
response
.
HttpVersion
==
HttpHeader
.
Version20
)
{
{
// do not send to the remote endpoint
response
.
Http2IgnoreBodyFrames
=
true
;
response
.
Http2BodyData
=
new
MemoryStream
();
response
.
Http2BodyData
=
new
MemoryStream
();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
...
@@ -166,6 +176,10 @@ namespace Titanium.Web.Proxy.EventArguments
...
@@ -166,6 +176,10 @@ namespace Titanium.Web.Proxy.EventArguments
response
.
ReadHttp2BeforeHandlerTaskCompletionSource
.
SetResult
(
true
);
response
.
ReadHttp2BeforeHandlerTaskCompletionSource
.
SetResult
(
true
);
await
tcs
.
Task
;
await
tcs
.
Task
;
// Now set the flag to true
// So that next time we can deliver body from cache
response
.
IsBodyRead
=
true
;
}
}
else
else
{
{
...
...
src/Titanium.Web.Proxy/Http/RequestResponseBase.cs
View file @
42a5ee99
...
@@ -56,6 +56,15 @@ namespace Titanium.Web.Proxy.Http
...
@@ -56,6 +56,15 @@ namespace Titanium.Web.Proxy.Http
internal
MemoryStream
Http2BodyData
;
internal
MemoryStream
Http2BodyData
;
internal
bool
Http2IgnoreBodyFrames
;
internal
Task
Http2BeforeHandlerTask
;
/// <summary>
/// Priority used only in HTTP/2
/// </summary>
internal
long
?
Priority
;
/// <summary>
/// <summary>
/// Keeps the body data after the session is finished.
/// Keeps the body data after the session is finished.
/// </summary>
/// </summary>
...
@@ -201,6 +210,8 @@ namespace Titanium.Web.Proxy.Http
...
@@ -201,6 +210,8 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
/// </summary>
internal
bool
Locked
{
get
;
set
;
}
internal
bool
Locked
{
get
;
set
;
}
internal
bool
BodyAvailable
=>
BodyInternal
!=
null
;
internal
abstract
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
);
internal
abstract
void
EnsureBodyAvailable
(
bool
throwWhenNotReadYet
=
true
);
/// <summary>
/// <summary>
...
...
src/Titanium.Web.Proxy/Http2/Http2Helper.cs
View file @
42a5ee99
...
@@ -2,10 +2,12 @@
...
@@ -2,10 +2,12 @@
using
System
;
using
System
;
using
System.Collections.Concurrent
;
using
System.Collections.Concurrent
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Diagnostics
;
using
System.IO
;
using
System.IO
;
using
System.Net
;
using
System.Net
;
using
System.Threading
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Compression
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Exceptions
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Http
;
...
@@ -128,22 +130,56 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -128,22 +130,56 @@ namespace Titanium.Web.Proxy.Http2
//System.Diagnostics.Debug.WriteLine("CONN: " + connectionId + ", CLIENT: " + isClient + ", STREAM: " + streamId + ", TYPE: " + type);
//System.Diagnostics.Debug.WriteLine("CONN: " + connectionId + ", CLIENT: " + isClient + ", STREAM: " + streamId + ", TYPE: " + type);
if
(
type
==
0
/* data */
)
if
(
type
==
0
/* data */
)
{
{
bool
padded
=
(
flags
&
(
int
)
Http2FrameFlag
.
Padded
)
!=
0
;
bool
endStreamFlag
=
(
flags
&
(
int
)
Http2FrameFlag
.
EndStream
)
!=
0
;
bool
endStreamFlag
=
(
flags
&
(
int
)
Http2FrameFlag
.
EndStream
)
!=
0
;
if
(
endStreamFlag
)
if
(
endStreamFlag
)
{
{
endStream
=
true
;
endStream
=
true
;
}
}
if
(
rr
.
Http2IgnoreBodyFrames
)
{
sendPacket
=
false
;
}
if
(
rr
.
ReadHttp2BodyTaskCompletionSource
!=
null
)
if
(
rr
.
ReadHttp2BodyTaskCompletionSource
!=
null
)
{
{
// Get body method was called in the "before" event handler
// Get body method was called in the "before" event handler
var
data
=
rr
.
Http2BodyData
;
var
data
=
rr
.
Http2BodyData
;
data
.
Write
(
buffer
,
0
,
length
);
int
offset
=
0
;
if
(
padded
)
{
offset
++;
length
--;
length
-=
buffer
[
0
];
}
data
.
Write
(
buffer
,
offset
,
length
);
if
(
endStream
)
if
(
endStream
)
{
{
rr
.
Body
=
data
.
ToArray
();
var
body
=
data
.
ToArray
();
if
(
rr
.
ContentEncoding
!=
null
)
{
using
(
var
ms
=
new
MemoryStream
())
{
using
(
var
zip
=
DecompressionFactory
.
Create
(
rr
.
ContentEncoding
,
new
MemoryStream
(
body
)))
{
zip
.
CopyTo
(
ms
);
}
body
=
ms
.
ToArray
();
}
}
if
(!
rr
.
BodyAvailable
)
{
rr
.
Body
=
body
;
}
rr
.
IsBodyRead
=
true
;
rr
.
IsBodyRead
=
true
;
var
tcs
=
rr
.
ReadHttp2BodyTaskCompletionSource
;
var
tcs
=
rr
.
ReadHttp2BodyTaskCompletionSource
;
...
@@ -155,6 +191,13 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -155,6 +191,13 @@ namespace Titanium.Web.Proxy.Http2
}
}
rr
.
Http2BodyData
=
null
;
rr
.
Http2BodyData
=
null
;
if
(
rr
.
Http2BeforeHandlerTask
!=
null
)
{
await
rr
.
Http2BeforeHandlerTask
;
}
await
sendBody
(
remoteSettings
,
rr
,
headerBuffer
,
buffer
,
output
);
}
}
}
}
}
}
...
@@ -173,11 +216,14 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -173,11 +216,14 @@ namespace Titanium.Web.Proxy.Http2
if
(
padded
)
if
(
padded
)
{
{
offset
=
1
;
offset
=
1
;
breakpoint
();
}
}
if
(
priority
)
if
(
priority
)
{
{
offset
+=
5
;
var
priorityData
=
((
long
)
buffer
[
offset
++]
<<
32
)
+
((
long
)
buffer
[
offset
++]
<<
24
)
+
(
buffer
[
offset
++]
<<
16
)
+
(
buffer
[
offset
++]
<<
8
)
+
buffer
[
offset
++];
rr
.
Priority
=
priorityData
;
}
}
int
dataLength
=
length
-
offset
;
int
dataLength
=
length
-
offset
;
...
@@ -212,6 +258,7 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -212,6 +258,7 @@ namespace Titanium.Web.Proxy.Http2
request
.
HttpVersion
=
HttpVersion
.
Version20
;
request
.
HttpVersion
=
HttpVersion
.
Version20
;
request
.
Method
=
headerListener
.
Method
;
request
.
Method
=
headerListener
.
Method
;
request
.
OriginalUrl
=
headerListener
.
Path
;
request
.
OriginalUrl
=
headerListener
.
Path
;
request
.
RequestUri
=
headerListener
.
GetUri
();
request
.
RequestUri
=
headerListener
.
GetUri
();
}
}
else
else
...
@@ -227,91 +274,43 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -227,91 +274,43 @@ namespace Titanium.Web.Proxy.Http2
exceptionFunc
(
new
ProxyHttpException
(
"Failed to decode HTTP/2 headers"
,
ex
,
args
));
exceptionFunc
(
new
ProxyHttpException
(
"Failed to decode HTTP/2 headers"
,
ex
,
args
));
}
}
if
(!
endHeaders
)
{
breakpoint
();
}
if
(
endHeaders
)
if
(
endHeaders
)
{
{
var
tcs
=
new
TaskCompletionSource
<
bool
>();
var
tcs
=
new
TaskCompletionSource
<
bool
>();
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
tcs
;
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
tcs
;
var
handler
=
onBeforeRequestResponse
(
args
);
var
handler
=
onBeforeRequestResponse
(
args
);
rr
.
Http2BeforeHandlerTask
=
handler
;
if
(
handler
==
await
Task
.
WhenAny
(
tcs
.
Task
,
handler
))
if
(
handler
==
await
Task
.
WhenAny
(
tcs
.
Task
,
handler
))
{
{
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
null
;
rr
.
ReadHttp2BeforeHandlerTaskCompletionSource
=
null
;
tcs
.
SetResult
(
true
);
tcs
.
SetResult
(
true
);
}
await
sendHeader
(
remoteSettings
,
headerBuffer
,
rr
,
endStream
,
output
);
rr
.
Locked
=
true
;
var
encoder
=
new
Encoder
(
remoteSettings
.
HeaderTableSize
);
var
ms
=
new
MemoryStream
();
var
writer
=
new
BinaryWriter
(
ms
);
if
(
priority
)
{
writer
.
Write
(
buffer
,
padded
?
1
:
0
,
5
);
}
if
(
isClient
)
{
var
request
=
(
Request
)
rr
;
encoder
.
EncodeHeader
(
writer
,
":method"
,
request
.
Method
);
encoder
.
EncodeHeader
(
writer
,
":authority"
,
request
.
RequestUri
.
Host
);
encoder
.
EncodeHeader
(
writer
,
":scheme"
,
request
.
RequestUri
.
Scheme
);
encoder
.
EncodeHeader
(
writer
,
":path"
,
request
.
RequestUriString
,
false
,
HpackUtil
.
IndexType
.
None
,
false
);
}
}
else
else
{
{
var
response
=
(
Response
)
rr
;
rr
.
Http2IgnoreBodyFrames
=
true
;
encoder
.
EncodeHeader
(
writer
,
":status"
,
response
.
StatusCode
.
ToString
());
}
}
foreach
(
var
header
in
rr
.
Headers
)
rr
.
Locked
=
true
;
{
encoder
.
EncodeHeader
(
writer
,
header
.
Name
.
ToLower
(),
header
.
Value
);
}
}
var
data
=
ms
.
ToArray
();
sendPacket
=
false
;
int
newLength
=
data
.
Length
;
//if (newLength == length)
//{
// var x = data;
// for (int i = 0; i < x.Length; i++)
// {
// if (i >= buffer.Length || buffer[i] != x[i])
// {
// ;
// }
// }
//}
headerBuffer
[
0
]
=
(
byte
)((
newLength
>>
16
)
&
0xff
);
headerBuffer
[
1
]
=
(
byte
)((
newLength
>>
8
)
&
0xff
);
headerBuffer
[
2
]
=
(
byte
)(
newLength
&
0xff
);
if
(
padded
)
{
// clear the padding flag
headerBuffer
[
4
]
=
(
byte
)(
flags
&
~((
int
)
Http2FrameFlag
.
Padded
));
}
}
else
if
(
type
==
5
/* push_promise */
)
//var headerListener2 = new MyHeaderListener2(
{
// (name, value) =>
breakpoint
();
// {
// System.Diagnostics.Debug.WriteLine("LL: " + name + ": " + value);
// });
//var decoder2 = new Decoder(8192, headerTableSize);
//decoder2.Decode(new BinaryReader(new MemoryStream(buffer, offset, dataLength)),
// headerListener2);
//decoder2.EndHeaderBlock();
await
output
.
WriteAsync
(
headerBuffer
,
0
,
headerBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
data
,
0
,
data
.
Length
/*, cancellationToken*/
);
}
}
else
if
(
type
==
9
/* continuation */
)
sendPacket
=
false
;
{
// todo: implementing this type is mandatory for multi-part headers
breakpoint
();
}
}
else
if
(
type
==
4
/* settings */
)
else
if
(
type
==
4
/* settings */
)
{
{
...
@@ -387,6 +386,105 @@ namespace Titanium.Web.Proxy.Http2
...
@@ -387,6 +386,105 @@ namespace Titanium.Web.Proxy.Http2
}
}
}
}
[
Conditional
(
"DEBUG"
)]
private
static
void
breakpoint
()
{
// when this method is called something received which is not yet implemented
;
}
private
static
async
Task
sendHeader
(
Http2Settings
settings
,
byte
[]
headerBuffer
,
RequestResponseBase
rr
,
bool
endStream
,
Stream
output
)
{
var
encoder
=
new
Encoder
(
settings
.
HeaderTableSize
);
var
ms
=
new
MemoryStream
();
var
writer
=
new
BinaryWriter
(
ms
);
if
(
rr
.
Priority
.
HasValue
)
{
long
p
=
rr
.
Priority
.
Value
;
writer
.
Write
((
byte
)((
p
>>
32
)
&
0xff
));
writer
.
Write
((
byte
)((
p
>>
24
)
&
0xff
));
writer
.
Write
((
byte
)((
p
>>
16
)
&
0xff
));
writer
.
Write
((
byte
)((
p
>>
8
)
&
0xff
));
writer
.
Write
((
byte
)(
p
&
0xff
));
}
if
(
rr
is
Request
request
)
{
encoder
.
EncodeHeader
(
writer
,
":method"
,
request
.
Method
);
encoder
.
EncodeHeader
(
writer
,
":authority"
,
request
.
RequestUri
.
Host
);
encoder
.
EncodeHeader
(
writer
,
":scheme"
,
request
.
RequestUri
.
Scheme
);
encoder
.
EncodeHeader
(
writer
,
":path"
,
request
.
RequestUriString
,
false
,
HpackUtil
.
IndexType
.
None
,
false
);
}
else
{
var
response
=
(
Response
)
rr
;
encoder
.
EncodeHeader
(
writer
,
":status"
,
response
.
StatusCode
.
ToString
());
}
foreach
(
var
header
in
rr
.
Headers
)
{
encoder
.
EncodeHeader
(
writer
,
header
.
Name
.
ToLower
(),
header
.
Value
);
}
var
data
=
ms
.
ToArray
();
int
newLength
=
data
.
Length
;
headerBuffer
[
0
]
=
(
byte
)((
newLength
>>
16
)
&
0xff
);
headerBuffer
[
1
]
=
(
byte
)((
newLength
>>
8
)
&
0xff
);
headerBuffer
[
2
]
=
(
byte
)(
newLength
&
0xff
);
headerBuffer
[
3
]
=
1
;
// type: header
int
flags
=
(
int
)
Http2FrameFlag
.
EndHeaders
;
if
(
endStream
)
{
flags
|=
(
int
)
Http2FrameFlag
.
EndStream
;
}
if
(
rr
.
Priority
.
HasValue
)
{
flags
|=
(
int
)
Http2FrameFlag
.
Priority
;
}
headerBuffer
[
4
]
=
(
byte
)
flags
;
// clear the padding flag
//headerBuffer[4] = (byte)(flags & ~((int)Http2FrameFlag.Padded));
// send the header
await
output
.
WriteAsync
(
headerBuffer
,
0
,
headerBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
data
,
0
,
data
.
Length
/*, cancellationToken*/
);
}
private
static
async
Task
sendBody
(
Http2Settings
settings
,
RequestResponseBase
rr
,
byte
[]
headerBuffer
,
byte
[]
buffer
,
Stream
output
)
{
var
body
=
rr
.
CompressBodyAndUpdateContentLength
();
await
sendHeader
(
settings
,
headerBuffer
,
rr
,
!(
rr
.
HasBody
&&
rr
.
IsBodyRead
),
output
);
if
(
rr
.
HasBody
&&
rr
.
IsBodyRead
)
{
int
pos
=
0
;
while
(
pos
<
body
.
Length
)
{
int
bodyFrameLength
=
Math
.
Min
(
buffer
.
Length
,
body
.
Length
-
pos
);
Buffer
.
BlockCopy
(
body
,
pos
,
buffer
,
0
,
bodyFrameLength
);
pos
+=
bodyFrameLength
;
headerBuffer
[
0
]
=
(
byte
)((
bodyFrameLength
>>
16
)
&
0xff
);
headerBuffer
[
1
]
=
(
byte
)((
bodyFrameLength
>>
8
)
&
0xff
);
headerBuffer
[
2
]
=
(
byte
)(
bodyFrameLength
&
0xff
);
headerBuffer
[
3
]
=
0
;
// type: data
headerBuffer
[
4
]
=
pos
<
body
.
Length
?
(
byte
)
0
:
(
byte
)(
int
)
Http2FrameFlag
.
EndStream
;
await
output
.
WriteAsync
(
headerBuffer
,
0
,
headerBuffer
.
Length
/*, cancellationToken*/
);
await
output
.
WriteAsync
(
buffer
,
0
,
bodyFrameLength
/*, cancellationToken*/
);
}
}
else
{
;
}
}
private
static
async
Task
<
int
>
forceRead
(
Stream
input
,
byte
[]
buffer
,
int
offset
,
int
bytesToRead
,
private
static
async
Task
<
int
>
forceRead
(
Stream
input
,
byte
[]
buffer
,
int
offset
,
int
bytesToRead
,
CancellationToken
cancellationToken
)
CancellationToken
cancellationToken
)
{
{
...
...
src/Titanium.Web.Proxy/ResponseHandler.cs
View file @
42a5ee99
...
@@ -125,7 +125,6 @@ namespace Titanium.Web.Proxy
...
@@ -125,7 +125,6 @@ namespace Titanium.Web.Proxy
}
}
args
.
TimeLine
[
"Response Sent"
]
=
DateTime
.
Now
;
args
.
TimeLine
[
"Response Sent"
]
=
DateTime
.
Now
;
}
}
/// <summary>
/// <summary>
...
...
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