Commit 7330b5c3 authored by Honfika's avatar Honfika

allow to modify HTTP/2 ehader

parent 29ffc5b9
......@@ -177,6 +177,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
}
});
e.HttpClient.Response.Headers.AddHeader("X-Titanium-Header", "HTTP/2 works");
//if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Http2)
//{
//}
......
......@@ -61,7 +61,9 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <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)
......@@ -116,10 +118,9 @@ namespace Titanium.Web.Proxy.Http2.Hpack
}
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);
}
......@@ -309,7 +310,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
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;
}
......@@ -336,7 +337,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
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;
......@@ -513,7 +514,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <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;
......
......@@ -154,7 +154,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
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.
......@@ -180,12 +180,12 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// <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>
......@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
while (index <= Length)
{
var entry = Get(index);
if (!HpackUtil.Equals(name, entry.Name))
if (!name.Equals(entry.Name, StringComparison.OrdinalIgnoreCase))
{
break;
}
......@@ -227,7 +227,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
/// 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);
......@@ -237,7 +237,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
for (int index = length; index > 0; index--)
{
var entry = Get(index);
string name = entry.Name;
string name = entry.Name.ToLower();
ret[name] = index;
}
......
......@@ -99,6 +99,7 @@ namespace Titanium.Web.Proxy.Http2
return;
}
bool sendPacket = true;
bool endStream = false;
SessionEventArgs args = null;
......@@ -210,7 +211,7 @@ namespace Titanium.Web.Proxy.Http2
var request = args.HttpClient.Request;
request.HttpVersion = HttpVersion.Version20;
request.Method = headerListener.Method;
request.OriginalUrl = headerListener.Status;
request.OriginalUrl = headerListener.Path;
request.RequestUri = headerListener.GetUri();
}
else
......@@ -240,7 +241,77 @@ namespace Titanium.Web.Proxy.Http2
}
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
{
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;
//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));
}
//var headerListener2 = new MyHeaderListener2(
// (name, value) =>
// {
// 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*/);
}
sendPacket = false;
}
else if (type == 4 /* settings */)
{
......@@ -296,9 +367,12 @@ namespace Titanium.Web.Proxy.Http2
//System.Diagnostics.Debug.WriteLine("REMOVED CONN: " + connectionId + ", CLIENT: " + isClient + ", STREAM: " + streamId + ", TYPE: " + type);
}
if (sendPacket)
{
// do not cancel the write operation
await output.WriteAsync(headerBuffer, 0, headerBuffer.Length/*, cancellationToken*/);
await output.WriteAsync(buffer, 0, length/*, cancellationToken*/);
await output.WriteAsync(headerBuffer, 0, headerBuffer.Length /*, cancellationToken*/);
await output.WriteAsync(buffer, 0, length /*, cancellationToken*/);
}
if (cancellationToken.IsCancellationRequested)
{
......
......@@ -35,13 +35,20 @@ namespace Titanium.Web.Proxy.Models
{
if (string.IsNullOrEmpty(name))
{
throw new Exception("Name cannot be null");
throw new Exception("Name cannot be null or empty");
}
Name = name.Trim();
Value = value.Trim();
}
protected HttpHeader(string name, string value, bool headerEntry)
{
// special header entry created in inherited class with empty name
Name = name.Trim();
Value = value.Trim();
}
/// <summary>
/// Header Name.
/// </summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment