Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

allow to modify HTTP/2 header #587

Merged
merged 4 commits into from
Apr 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,21 @@ await Dispatcher.InvokeAsync(() =>

private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)
{
if (e.HttpClient.ConnectRequest?.TunnelType != TunnelType.Http2)
{
return;
}

SessionListItem item = null;
await Dispatcher.InvokeAsync(() => { item = addSession(e); });

//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//{
//}

//if (!e.HttpClient.Request.RequestUri.ToString().Contains("/mail/u/"))
// return;

if (e.HttpClient.Request.HasBody)
{
e.HttpClient.Request.KeepBody = true;
Expand All @@ -168,6 +176,11 @@ private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)

private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
{
if (e.HttpClient.ConnectRequest?.TunnelType != TunnelType.Http2)
{
return;
}

SessionListItem item = null;
await Dispatcher.InvokeAsync(() =>
{
Expand All @@ -177,9 +190,9 @@ await Dispatcher.InvokeAsync(() =>
}
});

//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//{
//}
//e.HttpClient.Response.Headers.AddHeader("X-Titanium-Header", "HTTP/2 works");

//e.SetResponseBody(Encoding.ASCII.GetBytes("TITANIUMMMM!!!!"));

if (item != null)
{
Expand Down
19 changes: 19 additions & 0 deletions src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public class SessionEventArgs : SessionEventArgsBase
/// </summary>
private bool reRequest;

/// <summary>
/// Is this session a HTTP/2 promise?
/// </summary>
public bool IsPromise { get; internal set; }

/// <summary>
/// Constructor to initialize the proxy
/// </summary>
Expand Down Expand Up @@ -91,6 +96,9 @@ private async Task readRequestBodyAsync(CancellationToken cancellationToken)
{
if (request.HttpVersion == HttpHeader.Version20)
{
// do not send to the remote endpoint
request.Http2IgnoreBodyFrames = true;

request.Http2BodyData = new MemoryStream();

var tcs = new TaskCompletionSource<bool>();
Expand All @@ -100,6 +108,10 @@ private async Task readRequestBodyAsync(CancellationToken cancellationToken)
request.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true);

await tcs.Task;

// Now set the flag to true
// So that next time we can deliver body from cache
request.IsBodyRead = true;
}
else
{
Expand Down Expand Up @@ -157,6 +169,9 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken)
{
if (response.HttpVersion == HttpHeader.Version20)
{
// do not send to the remote endpoint
response.Http2IgnoreBodyFrames = true;

response.Http2BodyData = new MemoryStream();

var tcs = new TaskCompletionSource<bool>();
Expand All @@ -166,6 +181,10 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken)
response.ReadHttp2BeforeHandlerTaskCompletionSource.SetResult(true);

await tcs.Task;

// Now set the flag to true
// So that next time we can deliver body from cache
response.IsBodyRead = true;
}
else
{
Expand Down
11 changes: 11 additions & 0 deletions src/Titanium.Web.Proxy/Http/RequestResponseBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ public abstract class RequestResponseBase

internal MemoryStream Http2BodyData;

internal bool Http2IgnoreBodyFrames;

internal Task Http2BeforeHandlerTask;

/// <summary>
/// Priority used only in HTTP/2
/// </summary>
internal long? Priority;

/// <summary>
/// Keeps the body data after the session is finished.
/// </summary>
Expand Down Expand Up @@ -201,6 +210,8 @@ internal set
/// </summary>
internal bool Locked { get; set; }

internal bool BodyAvailable => BodyInternal != null;

internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true);

/// <summary>
Expand Down
13 changes: 7 additions & 6 deletions src/Titanium.Web.Proxy/Http2/Hpack/Encoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ public Encoder(int maxHeaderTableSize)
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="sensitive">If set to <c>true</c> sensitive.</param>
public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false)
/// <param name="indexType">Index type.</param>
/// <param name="useStaticName">Use static name.</param>
public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false, HpackUtil.IndexType indexType = HpackUtil.IndexType.Incremental, bool useStaticName = true)
{
// If the header value is sensitive then it must never be indexed
if (sensitive)
Expand Down Expand Up @@ -116,10 +118,9 @@ public void EncodeHeader(BinaryWriter output, string name, string value, bool se
}
else
{
int nameIndex = getNameIndex(name);
int nameIndex = useStaticName ? getNameIndex(name) : -1;
ensureCapacity(headerSize);

var indexType = HpackUtil.IndexType.Incremental;
encodeLiteral(output, name, value, indexType, nameIndex);
add(name, value);
}
Expand Down Expand Up @@ -309,7 +310,7 @@ private HeaderEntry getEntry(string name, string value)
int i = index(h);
for (var e = headerFields[i]; e != null; e = e.Next)
{
if (e.Hash == h && Equals(name, e.Name) && Equals(value, e.Value))
if (e.Hash == h && name.Equals(e.Name, StringComparison.OrdinalIgnoreCase) && Equals(value, e.Value))
{
return e;
}
Expand All @@ -336,7 +337,7 @@ private int getIndex(string name)
int index = -1;
for (var e = headerFields[i]; e != null; e = e.Next)
{
if (e.Hash == h && HpackUtil.Equals(name, e.Name))
if (e.Hash == h && name.Equals(e.Name, StringComparison.OrdinalIgnoreCase))
{
index = e.Index;
break;
Expand Down Expand Up @@ -513,7 +514,7 @@ private class HeaderEntry : HttpHeader
/// <param name="value">Value.</param>
/// <param name="index">Index.</param>
/// <param name="next">Next.</param>
public HeaderEntry(int hash, string name, string value, int index, HeaderEntry next) : base(name, value)
public HeaderEntry(int hash, string name, string value, int index, HeaderEntry next) : base(name, value, true)
{
Index = index;
Hash = hash;
Expand Down
12 changes: 6 additions & 6 deletions src/Titanium.Web.Proxy/Http2/Hpack/StaticTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public static class StaticTable
new HttpHeader("WWW-Authenticate", string.Empty)
};

private static readonly Dictionary<string, int> staticIndexByName = CreateMap();
private static readonly Dictionary<string, int> staticIndexByName = createMap();

/// <summary>
/// The number of header fields in the static table.
Expand All @@ -180,12 +180,12 @@ public static HttpHeader Get(int index)
/// <param name="name">Name.</param>
public static int GetIndex(string name)
{
if (!staticIndexByName.ContainsKey(name))
if (!staticIndexByName.TryGetValue(name, out int index))
{
return -1;
}

return staticIndexByName[name];
return index;
}

/// <summary>
Expand All @@ -207,7 +207,7 @@ public static int GetIndex(string name, string value)
while (index <= Length)
{
var entry = Get(index);
if (!HpackUtil.Equals(name, entry.Name))
if (!name.Equals(entry.Name, StringComparison.OrdinalIgnoreCase))
{
break;
}
Expand All @@ -227,7 +227,7 @@ public static int GetIndex(string name, string value)
/// create a map of header name to index value to allow quick lookup
/// </summary>
/// <returns>The map.</returns>
private static Dictionary<string, int> CreateMap()
private static Dictionary<string, int> createMap()
{
int length = staticTable.Count;
var ret = new Dictionary<string, int>(length);
Expand All @@ -237,7 +237,7 @@ private static Dictionary<string, int> CreateMap()
for (int index = length; index > 0; index--)
{
var entry = Get(index);
string name = entry.Name;
string name = entry.Name.ToLower();
ret[name] = index;
}

Expand Down
14 changes: 14 additions & 0 deletions src/Titanium.Web.Proxy/Http2/Http2FrameFlag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Titanium.Web.Proxy.Http2
{
[Flags]
internal enum Http2FrameFlag : byte
{
Ack = 0x01,
EndStream = 0x01,
EndHeaders = 0x04,
Padded = 0x08,
Priority = 0x20,
}
}
32 changes: 32 additions & 0 deletions src/Titanium.Web.Proxy/Http2/Http2FrameHeader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Titanium.Web.Proxy.Http2
{
internal class Http2FrameHeader
{
public int Length;

public Http2FrameType Type;

public Http2FrameFlag Flags;

public int StreamId;

public byte[] Buffer;

public byte[] CopyToBuffer()
{
int length = Length;
var buf = /*new byte[9];*/Buffer;
buf[0] = (byte)((length >> 16) & 0xff);
buf[1] = (byte)((length >> 8) & 0xff);
buf[2] = (byte)(length & 0xff);
buf[3] = (byte)Type;
buf[4] = (byte)Flags;
int streamId = StreamId;
//buf[5] = (byte)((streamId >> 24) & 0xff);
//buf[6] = (byte)((streamId >> 16) & 0xff);
//buf[7] = (byte)((streamId >> 8) & 0xff);
//buf[8] = (byte)(streamId & 0xff);
return buf;
}
}
}
16 changes: 16 additions & 0 deletions src/Titanium.Web.Proxy/Http2/Http2FrameType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Titanium.Web.Proxy.Http2
{
internal enum Http2FrameType : byte
{
Data = 0x00,
Headers = 0x01,
Priority = 0x02,
RstStream = 0x03,
Settings = 0x04,
PushPromise = 0x05,
Ping = 0x06,
GoAway = 0x07,
WindowUpdate = 0x08,
Continuation = 0x09,
}
}
Loading