培训考核三期,新版培训,网页版培训登录器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

198 lines
7.7 KiB

#if (!UNITY_WEBGL || UNITY_EDITOR) && !BESTHTTP_DISABLE_ALTERNATE_SSL && !BESTHTTP_DISABLE_HTTP2
using System;
using System.Collections.Generic;
namespace BestHTTP.Connections.HTTP2
{
sealed class HeaderTable
{
// https://http2.github.io/http2-spec/compression.html#static.table.definition
// Valid indexes starts with 1, so there's an empty entry.
static string[] StaticTableValues = new string[] { string.Empty, string.Empty, "GET", "POST", "/", "/index.html", "http", "https", "200", "204", "206", "304", "400", "404", "500", string.Empty, "gzip, deflate" };
// https://http2.github.io/http2-spec/compression.html#static.table.definition
// Valid indexes starts with 1, so there's an empty entry.
static string[] StaticTable = new string[62]
{
string.Empty,
":authority",
":method", // GET
":method", // POST
":path", // /
":path", // index.html
":scheme", // http
":scheme", // https
":status", // 200
":status", // 204
":status", // 206
":status", // 304
":status", // 400
":status", // 404
":status", // 500
"accept-charset",
"accept-encoding", // gzip, deflate
"accept-language",
"accept-ranges",
"accept",
"access-control-allow-origin",
"age",
"allow",
"authorization",
"cache-control",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-range",
"content-type",
"cookie",
"date",
"etag",
"expect",
"expires",
"from",
"host",
"if-match",
"if-modified-since",
"if-none-match",
"if-range",
"if-unmodified-since",
"last-modified",
"link",
"location",
"max-forwards",
"proxy-authenticate",
"proxy-authorization",
"range",
"referer",
"refresh",
"retry-after",
"server",
"set-cookie",
"strict-transport-security",
"transfer-encoding",
"user-agent",
"vary",
"via",
"www-authenticate",
};
public UInt32 DynamicTableSize { get; private set; }
public UInt32 MaxDynamicTableSize {
get { return this._maxDynamicTableSize; }
set
{
this._maxDynamicTableSize = value;
EvictEntries(0);
}
}
private UInt32 _maxDynamicTableSize;
private List<KeyValuePair<string, string>> DynamicTable = new List<KeyValuePair<string, string>>();
private HTTP2SettingsRegistry settingsRegistry;
public HeaderTable(HTTP2SettingsRegistry registry)
{
this.settingsRegistry = registry;
this.MaxDynamicTableSize = this.settingsRegistry[HTTP2Settings.HEADER_TABLE_SIZE];
}
public KeyValuePair<UInt32, UInt32> GetIndex(string key, string value)
{
for (int i = 0; i < DynamicTable.Count; ++i)
{
var kvp = DynamicTable[i];
// Exact match for both key and value
if (kvp.Key.Equals(key, StringComparison.OrdinalIgnoreCase) && kvp.Value.Equals(value, StringComparison.OrdinalIgnoreCase))
return new KeyValuePair<UInt32, UInt32>((UInt32)(StaticTable.Length + i), (UInt32)(StaticTable.Length + i));
}
KeyValuePair<UInt32, UInt32> bestMatch = new KeyValuePair<UInt32, UInt32>(0, 0);
for (int i = 0; i < StaticTable.Length; ++i)
{
if (StaticTable[i].Equals(key, StringComparison.OrdinalIgnoreCase))
{
if (i < StaticTableValues.Length && !string.IsNullOrEmpty(StaticTableValues[i]) && StaticTableValues[i].Equals(value, StringComparison.OrdinalIgnoreCase))
return new KeyValuePair<UInt32, UInt32>((UInt32)i, (UInt32)i);
else
bestMatch = new KeyValuePair<UInt32, UInt32>((UInt32)i, 0);
}
}
return bestMatch;
}
public string GetKey(UInt32 index)
{
if (index < StaticTable.Length)
return StaticTable[index];
return this.DynamicTable[(int)(index - StaticTable.Length)].Key;
}
public KeyValuePair<string, string> GetHeader(UInt32 index)
{
if (index < StaticTable.Length)
return new KeyValuePair<string, string>(StaticTable[index],
index < StaticTableValues.Length ? StaticTableValues[index] : null);
return this.DynamicTable[(int)(index - StaticTable.Length)];
}
public void Add(KeyValuePair<string, string> header)
{
// https://http2.github.io/http2-spec/compression.html#calculating.table.size
// The size of an entry is the sum of its name's length in octets (as defined in Section 5.2),
// its value's length in octets, and 32.
UInt32 newHeaderSize = CalculateEntrySize(header);
EvictEntries(newHeaderSize);
// If the size of the new entry is less than or equal to the maximum size, that entry is added to the table.
// It is not an error to attempt to add an entry that is larger than the maximum size;
// an attempt to add an entry larger than the maximum size causes the table to be
// emptied of all existing entries and results in an empty table.
if (this.DynamicTableSize + newHeaderSize <= this.MaxDynamicTableSize)
{
this.DynamicTable.Insert(0, header);
this.DynamicTableSize += (UInt32)newHeaderSize;
}
}
private UInt32 CalculateEntrySize(KeyValuePair<string, string> entry)
{
return 32 + (UInt32)System.Text.Encoding.UTF8.GetByteCount(entry.Key) +
(UInt32)System.Text.Encoding.UTF8.GetByteCount(entry.Value);
}
private void EvictEntries(uint newHeaderSize)
{
// https://http2.github.io/http2-spec/compression.html#entry.addition
// Before a new entry is added to the dynamic table, entries are evicted from the end of the dynamic
// table until the size of the dynamic table is less than or equal to (maximum size - new entry size) or until the table is empty.
while (this.DynamicTableSize + newHeaderSize > this.MaxDynamicTableSize && this.DynamicTable.Count > 0)
{
KeyValuePair<string, string> entry = this.DynamicTable[this.DynamicTable.Count - 1];
this.DynamicTable.RemoveAt(this.DynamicTable.Count - 1);
this.DynamicTableSize -= CalculateEntrySize(entry);
}
}
public override string ToString()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder("[HeaderTable ");
sb.AppendFormat("DynamicTable count: {0}, DynamicTableSize: {1}, MaxDynamicTableSize: {2}, ", this.DynamicTable.Count, this.DynamicTableSize, this.MaxDynamicTableSize);
foreach(var kvp in this.DynamicTable)
sb.AppendFormat("\"{0}\": \"{1}\", ", kvp.Key, kvp.Value);
sb.Append("]");
return sb.ToString();
}
}
}
#endif