Commit 693694f7 authored by justcoding121's avatar justcoding121
parents eacb13d2 580bfb93
...@@ -13,6 +13,7 @@ using Titanium.Web.Proxy.Exceptions; ...@@ -13,6 +13,7 @@ using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http2;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Network.Tcp;
......
This diff is collapsed.
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class DynamicTable
{
// a circular queue of header fields
HttpHeader[] headerFields;
int head;
int tail;
/// <summary>
/// Return the maximum allowable size of the dynamic table.
/// </summary>
/// <value>
/// The capacity.
/// </value>
// ensure setCapacity creates the array
public int Capacity { get; private set; } = -1;
/// <summary>
/// Return the current size of the dynamic table.
/// This is the sum of the size of the entries.
/// </summary>
/// <value>
/// The size.
/// </value>
public int Size { get; private set; }
/// <summary>
/// Creates a new dynamic table with the specified initial capacity.
/// </summary>
/// <param name="initialCapacity">Initial capacity.</param>
public DynamicTable(int initialCapacity)
{
SetCapacity(initialCapacity);
}
/// <summary>
/// Return the number of header fields in the dynamic table.
/// </summary>
public int Length()
{
int length;
if (head < tail)
{
length = headerFields.Length - tail + head;
}
else
{
length = head - tail;
}
return length;
}
/// <summary>
/// Return the header field at the given index.
/// The first and newest entry is always at index 1,
/// and the oldest entry is at the index length().
/// </summary>
/// <returns>The entry.</returns>
/// <param name="index">Index.</param>
public HttpHeader GetEntry(int index)
{
if (index <= 0 || index > Length())
{
throw new IndexOutOfRangeException();
}
int i = head - index;
if (i < 0)
{
return headerFields[i + headerFields.Length];
}
return headerFields[i];
}
/// <summary>
/// Add the header field to the dynamic table.
/// Entries are evicted from the dynamic table until the size of the table
/// and the new header field is less than or equal to the table's capacity.
/// If the size of the new entry is larger than the table's capacity,
/// the dynamic table will be cleared.
/// </summary>
/// <param name="header">Header.</param>
public void Add(HttpHeader header)
{
int headerSize = header.Size;
if (headerSize > Capacity)
{
Clear();
return;
}
while (Size + headerSize > Capacity)
{
Remove();
}
headerFields[head++] = header;
Size += header.Size;
if (head == headerFields.Length)
{
head = 0;
}
}
/// <summary>
/// Remove and return the oldest header field from the dynamic table.
/// </summary>
public HttpHeader Remove()
{
var removed = headerFields[tail];
if (removed == null)
{
return null;
}
Size -= removed.Size;
headerFields[tail++] = null;
if (tail == headerFields.Length)
{
tail = 0;
}
return removed;
}
/// <summary>
/// Remove all entries from the dynamic table.
/// </summary>
public void Clear()
{
while (tail != head)
{
headerFields[tail++] = null;
if (tail == headerFields.Length)
{
tail = 0;
}
}
head = 0;
tail = 0;
Size = 0;
}
/// <summary>
/// Set the maximum size of the dynamic table.
/// Entries are evicted from the dynamic table until the size of the table
/// is less than or equal to the maximum size.
/// </summary>
/// <param name="capacity">Capacity.</param>
public void SetCapacity(int capacity)
{
if (capacity < 0)
{
throw new ArgumentException("Illegal Capacity: " + capacity);
}
// initially capacity will be -1 so init won't return here
if (Capacity == capacity)
{
return;
}
Capacity = capacity;
if (capacity == 0)
{
Clear();
}
else
{
// initially size will be 0 so remove won't be called
while (Size > capacity)
{
Remove();
}
}
int maxEntries = capacity / HttpHeader.HttpHeaderOverhead;
if (capacity % HttpHeader.HttpHeaderOverhead != 0)
{
maxEntries++;
}
// check if capacity change requires us to reallocate the array
if (headerFields != null && headerFields.Length == maxEntries)
{
return;
}
var tmp = new HttpHeader[maxEntries];
// initially length will be 0 so there will be no copy
int len = Length();
int cursor = tail;
for (int i = 0; i < len; i++)
{
var entry = headerFields[cursor++];
tmp[i] = entry;
if (cursor == headerFields.Length)
{
cursor = 0;
}
}
tail = 0;
head = tail + len;
headerFields = tmp;
}
}
}
This diff is collapsed.
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public static class HpackUtil
{
// Section 6.2. Literal Header Field Representation
public enum IndexType
{
Incremental, // Section 6.2.1. Literal Header Field with Incremental Indexing
None, // Section 6.2.2. Literal Header Field without Indexing
Never // Section 6.2.3. Literal Header Field never Indexed
}
// Appendix B: Huffman Codes
// http://tools.ietf.org/html/rfc7541#appendix-B
public static readonly int[] HuffmanCodes = {
0x1ff8,
0x7fffd8,
0xfffffe2,
0xfffffe3,
0xfffffe4,
0xfffffe5,
0xfffffe6,
0xfffffe7,
0xfffffe8,
0xffffea,
0x3ffffffc,
0xfffffe9,
0xfffffea,
0x3ffffffd,
0xfffffeb,
0xfffffec,
0xfffffed,
0xfffffee,
0xfffffef,
0xffffff0,
0xffffff1,
0xffffff2,
0x3ffffffe,
0xffffff3,
0xffffff4,
0xffffff5,
0xffffff6,
0xffffff7,
0xffffff8,
0xffffff9,
0xffffffa,
0xffffffb,
0x14,
0x3f8,
0x3f9,
0xffa,
0x1ff9,
0x15,
0xf8,
0x7fa,
0x3fa,
0x3fb,
0xf9,
0x7fb,
0xfa,
0x16,
0x17,
0x18,
0x0,
0x1,
0x2,
0x19,
0x1a,
0x1b,
0x1c,
0x1d,
0x1e,
0x1f,
0x5c,
0xfb,
0x7ffc,
0x20,
0xffb,
0x3fc,
0x1ffa,
0x21,
0x5d,
0x5e,
0x5f,
0x60,
0x61,
0x62,
0x63,
0x64,
0x65,
0x66,
0x67,
0x68,
0x69,
0x6a,
0x6b,
0x6c,
0x6d,
0x6e,
0x6f,
0x70,
0x71,
0x72,
0xfc,
0x73,
0xfd,
0x1ffb,
0x7fff0,
0x1ffc,
0x3ffc,
0x22,
0x7ffd,
0x3,
0x23,
0x4,
0x24,
0x5,
0x25,
0x26,
0x27,
0x6,
0x74,
0x75,
0x28,
0x29,
0x2a,
0x7,
0x2b,
0x76,
0x2c,
0x8,
0x9,
0x2d,
0x77,
0x78,
0x79,
0x7a,
0x7b,
0x7ffe,
0x7fc,
0x3ffd,
0x1ffd,
0xffffffc,
0xfffe6,
0x3fffd2,
0xfffe7,
0xfffe8,
0x3fffd3,
0x3fffd4,
0x3fffd5,
0x7fffd9,
0x3fffd6,
0x7fffda,
0x7fffdb,
0x7fffdc,
0x7fffdd,
0x7fffde,
0xffffeb,
0x7fffdf,
0xffffec,
0xffffed,
0x3fffd7,
0x7fffe0,
0xffffee,
0x7fffe1,
0x7fffe2,
0x7fffe3,
0x7fffe4,
0x1fffdc,
0x3fffd8,
0x7fffe5,
0x3fffd9,
0x7fffe6,
0x7fffe7,
0xffffef,
0x3fffda,
0x1fffdd,
0xfffe9,
0x3fffdb,
0x3fffdc,
0x7fffe8,
0x7fffe9,
0x1fffde,
0x7fffea,
0x3fffdd,
0x3fffde,
0xfffff0,
0x1fffdf,
0x3fffdf,
0x7fffeb,
0x7fffec,
0x1fffe0,
0x1fffe1,
0x3fffe0,
0x1fffe2,
0x7fffed,
0x3fffe1,
0x7fffee,
0x7fffef,
0xfffea,
0x3fffe2,
0x3fffe3,
0x3fffe4,
0x7ffff0,
0x3fffe5,
0x3fffe6,
0x7ffff1,
0x3ffffe0,
0x3ffffe1,
0xfffeb,
0x7fff1,
0x3fffe7,
0x7ffff2,
0x3fffe8,
0x1ffffec,
0x3ffffe2,
0x3ffffe3,
0x3ffffe4,
0x7ffffde,
0x7ffffdf,
0x3ffffe5,
0xfffff1,
0x1ffffed,
0x7fff2,
0x1fffe3,
0x3ffffe6,
0x7ffffe0,
0x7ffffe1,
0x3ffffe7,
0x7ffffe2,
0xfffff2,
0x1fffe4,
0x1fffe5,
0x3ffffe8,
0x3ffffe9,
0xffffffd,
0x7ffffe3,
0x7ffffe4,
0x7ffffe5,
0xfffec,
0xfffff3,
0xfffed,
0x1fffe6,
0x3fffe9,
0x1fffe7,
0x1fffe8,
0x7ffff3,
0x3fffea,
0x3fffeb,
0x1ffffee,
0x1ffffef,
0xfffff4,
0xfffff5,
0x3ffffea,
0x7ffff4,
0x3ffffeb,
0x7ffffe6,
0x3ffffec,
0x3ffffed,
0x7ffffe7,
0x7ffffe8,
0x7ffffe9,
0x7ffffea,
0x7ffffeb,
0xffffffe,
0x7ffffec,
0x7ffffed,
0x7ffffee,
0x7ffffef,
0x7fffff0,
0x3ffffee,
0x3fffffff // EOS
};
public static readonly byte[] HuffmanCodeLengths = {
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
30 // EOS
};
public const int HuffmanEos = 256;
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
using System.Text;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class HuffmanDecoder
{
/// <summary>
/// Huffman Decoder
/// </summary>
public static readonly HuffmanDecoder Instance = new HuffmanDecoder();
private readonly Node root;
/// <summary>
/// Creates a new Huffman decoder with the specified Huffman coding.
/// </summary>
private HuffmanDecoder()
{
// the Huffman codes indexed by symbol
var codes = HpackUtil.HuffmanCodes;
// the length of each Huffman code
var lengths = HpackUtil.HuffmanCodeLengths;
if (codes.Length != 257 || codes.Length != lengths.Length)
{
throw new ArgumentException("invalid Huffman coding");
}
root = BuildTree(codes, lengths);
}
/// <summary>
/// Decompresses the given Huffman coded string literal.
/// </summary>
/// <param name="buf">the string literal to be decoded</param>
/// <returns>the output stream for the compressed data</returns>
/// <exception cref="IOException">throws IOException if an I/O error occurs. In particular, an <code>IOException</code> may be thrown if the output stream has been closed.</exception>
public string Decode(byte[] buf)
{
var resultBuf = new byte[buf.Length * 2];
int resultSize = 0;
var node = root;
int current = 0;
int bits = 0;
for (int i = 0; i < buf.Length; i++)
{
int b = buf[i];
current = (current << 8) | b;
bits += 8;
while (bits >= 8)
{
int c = (current >> (bits - 8)) & 0xFF;
node = node.Children[c];
bits -= node.Bits;
if (node.IsTerminal)
{
if (node.Symbol == HpackUtil.HuffmanEos)
{
throw new IOException("EOS Decoded");
}
resultBuf[resultSize++] = (byte)node.Symbol;
node = root;
}
}
}
while (bits > 0)
{
int c = (current << (8 - bits)) & 0xFF;
node = node.Children[c];
if (node.IsTerminal && node.Bits <= bits)
{
bits -= node.Bits;
resultBuf[resultSize++] = (byte)node.Symbol;
node = root;
}
else
{
break;
}
}
// Section 5.2. String Literal Representation
// Padding not corresponding to the most significant bits of the code
// for the EOS symbol (0xFF) MUST be treated as a decoding error.
int mask = (1 << bits) - 1;
if ((current & mask) != mask)
{
throw new IOException("Invalid Padding");
}
return Encoding.UTF8.GetString(resultBuf, 0, resultSize);
}
private class Node
{
// terminal nodes have a symbol
public int Symbol { get; }
// number of bits matched by the node
public int Bits { get; }
// internal nodes have children
public Node[] Children { get; }
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanDecoder"/> class.
/// </summary>
public Node()
{
Symbol = 0;
Bits = 8;
Children = new Node[256];
}
/// <summary>
/// Initializes a new instance of the <see cref="HuffmanDecoder"/> class.
/// </summary>
/// <param name="symbol">the symbol the node represents</param>
/// <param name="bits">the number of bits matched by this node</param>
public Node(int symbol, int bits)
{
//assert(bits > 0 && bits <= 8);
Symbol = symbol;
Bits = bits;
Children = null;
}
public bool IsTerminal => Children == null;
}
private static Node BuildTree(int[] codes, byte[] lengths)
{
var root = new Node();
for (int i = 0; i < codes.Length; i++)
{
Insert(root, i, codes[i], lengths[i]);
}
return root;
}
private static void Insert(Node root, int symbol, int code, byte length)
{
// traverse tree using the most significant bytes of code
var current = root;
while (length > 8)
{
if (current.IsTerminal)
{
throw new InvalidDataException("invalid Huffman code: prefix not unique");
}
length -= 8;
int i = (code >> length) & 0xFF;
if (current.Children[i] == null)
{
current.Children[i] = new Node();
}
current = current.Children[i];
}
var terminal = new Node(symbol, length);
int shift = 8 - length;
int start = (code << shift) & 0xFF;
int end = 1 << shift;
for (int i = start; i < start + end; i++)
{
current.Children[i] = terminal;
}
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public class HuffmanEncoder
{
/// <summary>
/// Huffman Encoder
/// </summary>
public static readonly HuffmanEncoder Instance = new HuffmanEncoder();
/// <summary>
/// the Huffman codes indexed by symbol
/// </summary>
private readonly int[] codes = HpackUtil.HuffmanCodes;
/// <summary>
/// the length of each Huffman code
/// </summary>
private readonly byte[] lengths = HpackUtil.HuffmanCodeLengths;
/// <summary>
/// Compresses the input string literal using the Huffman coding.
/// </summary>
/// <param name="output">the output stream for the compressed data</param>
/// <param name="data">the string literal to be Huffman encoded</param>
/// <exception cref="IOException">if an I/O error occurs.</exception>
/// <see cref="Encode(BinaryWriter,byte[],int,int)"/>
public void Encode(BinaryWriter output, byte[] data)
{
Encode(output, data, 0, data.Length);
}
/// <summary>
/// Compresses the input string literal using the Huffman coding.
/// </summary>
/// <param name="output">the output stream for the compressed data</param>
/// <param name="data">the string literal to be Huffman encoded</param>
/// <param name="off">the start offset in the data</param>
/// <param name="len">the number of bytes to encode</param>
/// <exception cref="IOException">if an I/O error occurs. In particular, an <code>IOException</code> may be thrown if the output stream has been closed.</exception>
public void Encode(BinaryWriter output, byte[] data, int off, int len)
{
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (off < 0 || len < 0 || (off + len) < 0 || off > data.Length || (off + len) > data.Length)
{
throw new IndexOutOfRangeException();
}
if (len == 0)
{
return;
}
long current = 0L;
int n = 0;
for (int i = 0; i < len; i++)
{
int b = data[off + i] & 0xFF;
uint code = (uint)codes[b];
int nbits = lengths[b];
current <<= nbits;
current |= code;
n += nbits;
while (n >= 8)
{
n -= 8;
output.Write(((byte)(current >> n)));
}
}
if (n > 0)
{
current <<= (8 - n);
current |= (uint)(0xFF >> n); // this should be EOS symbol
output.Write((byte)current);
}
}
/// <summary>
/// Returns the number of bytes required to Huffman encode the input string literal.
/// </summary>
/// <returns>the number of bytes required to Huffman encode <code>data</code></returns>
/// <param name="data">the string literal to be Huffman encoded</param>
public int GetEncodedLength(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
long len = 0L;
foreach (byte b in data)
{
len += lengths[b];
}
return (int)((len + 7) >> 3);
}
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Titanium.Web.Proxy.Http2.Hpack
{
public interface IHeaderListener
{
/// <summary>
/// EmitHeader is called by the decoder during header field emission.
/// The name and value byte arrays must not be modified.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
/// <param name="sensitive">If set to <c>true</c> sensitive.</param>
void AddHeader(string name, string value, bool sensitive);
}
}
/*
* Copyright 2014 Twitter, Inc
* This file is a derivative work modified by Ringo Leese
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http2.Hpack
{
public static class StaticTable
{
/// <summary>
/// Appendix A: Static Table Definition
/// </summary>
/// <see cref="http://tools.ietf.org/html/rfc7541#appendix-A"/>
private static readonly List<HttpHeader> staticTable = new List<HttpHeader>()
{
/* 1 */
new HttpHeader(":authority", string.Empty),
/* 2 */
new HttpHeader(":method", "GET"),
/* 3 */
new HttpHeader(":method", "POST"),
/* 4 */
new HttpHeader(":path", "/"),
/* 5 */
new HttpHeader(":path", "/index.html"),
/* 6 */
new HttpHeader(":scheme", "http"),
/* 7 */
new HttpHeader(":scheme", "https"),
/* 8 */
new HttpHeader(":status", "200"),
/* 9 */
new HttpHeader(":status", "204"),
/* 10 */
new HttpHeader(":status", "206"),
/* 11 */
new HttpHeader(":status", "304"),
/* 12 */
new HttpHeader(":status", "400"),
/* 13 */
new HttpHeader(":status", "404"),
/* 14 */
new HttpHeader(":status", "500"),
/* 15 */
new HttpHeader("accept-charset", string.Empty),
/* 16 */
new HttpHeader("accept-encoding", "gzip, deflate"),
/* 17 */
new HttpHeader("accept-language", string.Empty),
/* 18 */
new HttpHeader("accept-ranges", string.Empty),
/* 19 */
new HttpHeader("accept", string.Empty),
/* 20 */
new HttpHeader("access-control-allow-origin", string.Empty),
/* 21 */
new HttpHeader("age", string.Empty),
/* 22 */
new HttpHeader("allow", string.Empty),
/* 23 */
new HttpHeader("authorization", string.Empty),
/* 24 */
new HttpHeader("cache-control", string.Empty),
/* 25 */
new HttpHeader("content-disposition", string.Empty),
/* 26 */
new HttpHeader("content-encoding", string.Empty),
/* 27 */
new HttpHeader("content-language", string.Empty),
/* 28 */
new HttpHeader("content-length", string.Empty),
/* 29 */
new HttpHeader("content-location", string.Empty),
/* 30 */
new HttpHeader("content-range", string.Empty),
/* 31 */
new HttpHeader("content-type", string.Empty),
/* 32 */
new HttpHeader("cookie", string.Empty),
/* 33 */
new HttpHeader("date", string.Empty),
/* 34 */
new HttpHeader("etag", string.Empty),
/* 35 */
new HttpHeader("expect", string.Empty),
/* 36 */
new HttpHeader("expires", string.Empty),
/* 37 */
new HttpHeader("from", string.Empty),
/* 38 */
new HttpHeader("host", string.Empty),
/* 39 */
new HttpHeader("if-match", string.Empty),
/* 40 */
new HttpHeader("if-modified-since", string.Empty),
/* 41 */
new HttpHeader("if-none-match", string.Empty),
/* 42 */
new HttpHeader("if-range", string.Empty),
/* 43 */
new HttpHeader("if-unmodified-since", string.Empty),
/* 44 */
new HttpHeader("last-modified", string.Empty),
/* 45 */
new HttpHeader("link", string.Empty),
/* 46 */
new HttpHeader("location", string.Empty),
/* 47 */
new HttpHeader("max-forwards", string.Empty),
/* 48 */
new HttpHeader("proxy-authenticate", string.Empty),
/* 49 */
new HttpHeader("proxy-authorization", string.Empty),
/* 50 */
new HttpHeader("range", string.Empty),
/* 51 */
new HttpHeader("referer", string.Empty),
/* 52 */
new HttpHeader("refresh", string.Empty),
/* 53 */
new HttpHeader("retry-after", string.Empty),
/* 54 */
new HttpHeader("server", string.Empty),
/* 55 */
new HttpHeader("set-cookie", string.Empty),
/* 56 */
new HttpHeader("strict-transport-security", string.Empty),
/* 57 */
new HttpHeader("transfer-encoding", string.Empty),
/* 58 */
new HttpHeader("user-agent", string.Empty),
/* 59 */
new HttpHeader("vary", string.Empty),
/* 60 */
new HttpHeader("via", string.Empty),
/* 61 */
new HttpHeader("www-authenticate", string.Empty)
};
private static readonly Dictionary<string, int> staticIndexByName = CreateMap();
/// <summary>
/// The number of header fields in the static table.
/// </summary>
/// <value>The length.</value>
public static int Length => staticTable.Count;
/// <summary>
/// Return the http header field at the given index value.
/// </summary>
/// <returns>The header field.</returns>
/// <param name="index">Index.</param>
public static HttpHeader Get(int index)
{
return staticTable[index - 1];
}
/// <summary>
/// Returns the lowest index value for the given header field name in the static table.
/// Returns -1 if the header field name is not in the static table.
/// </summary>
/// <returns>The index.</returns>
/// <param name="name">Name.</param>
public static int GetIndex(string name)
{
if (!staticIndexByName.ContainsKey(name))
{
return -1;
}
return staticIndexByName[name];
}
/// <summary>
/// Returns the index value for the given header field in the static table.
/// Returns -1 if the header field is not in the static table.
/// </summary>
/// <returns>The index.</returns>
/// <param name="name">Name.</param>
/// <param name="value">Value.</param>
public static int GetIndex(string name, string value)
{
int index = GetIndex(name);
if (index == -1)
{
return -1;
}
// Note this assumes all entries for a given header field are sequential.
while (index <= Length)
{
var entry = Get(index);
if (!HpackUtil.Equals(name, entry.Name))
{
break;
}
if (HpackUtil.Equals(value, entry.Value))
{
return index;
}
index++;
}
return -1;
}
/// <summary>
/// create a map of header name to index value to allow quick lookup
/// </summary>
/// <returns>The map.</returns>
private static Dictionary<string, int> CreateMap()
{
int length = staticTable.Count;
var ret = new Dictionary<string, int>(length);
// Iterate through the static table in reverse order to
// save the smallest index for a given name in the map.
for (int index = length; index > 0; index--)
{
var entry = Get(index);
string name = entry.Name;
ret[name] = index;
}
return ret;
}
}
}
\ No newline at end of file
#if NETCOREAPP2_1
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http2.Hpack;
namespace Titanium.Web.Proxy.Http2
{
[Flags]
internal enum Http2FrameFlag
{
Ack = 0x01,
EndStream = 0x01,
EndHeaders = 0x04,
Padded = 0x08,
Priority = 0x20,
}
internal class Http2Helper
{
/// <summary>
/// relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
/// as prefix
/// Usefull for websocket requests
/// Task-based Asynchronous Pattern
/// </summary>
/// <param name="clientStream"></param>
/// <param name="serverStream"></param>
/// <param name="bufferSize"></param>
/// <param name="onDataSend"></param>
/// <param name="onDataReceive"></param>
/// <param name="cancellationTokenSource"></param>
/// <param name="connectionId"></param>
/// <param name="exceptionFunc"></param>
/// <returns></returns>
internal static async Task SendHttp2(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive,
CancellationTokenSource cancellationTokenSource, Guid connectionId,
ExceptionHandler exceptionFunc)
{
// Now async relay all server=>client & client=>server data
var sendRelay =
CopyHttp2FrameAsync(clientStream, serverStream, onDataSend, bufferSize, connectionId,
true, cancellationTokenSource.Token);
var receiveRelay =
CopyHttp2FrameAsync(serverStream, clientStream, onDataReceive, bufferSize, connectionId,
false, cancellationTokenSource.Token);
await Task.WhenAny(sendRelay, receiveRelay);
cancellationTokenSource.Cancel();
await Task.WhenAll(sendRelay, receiveRelay);
}
private static async Task CopyHttp2FrameAsync(Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, Guid connectionId, bool isClient, CancellationToken cancellationToken)
{
var decoder = new Decoder(8192, 4096);
var headerBuffer = new byte[9];
var buffer = new byte[32768];
while (true)
{
int read = await ForceRead(input, headerBuffer, 0, 9, cancellationToken);
if (read != 9)
{
return;
}
int length = (headerBuffer[0] << 16) + (headerBuffer[1] << 8) + headerBuffer[2];
byte type = headerBuffer[3];
byte flags = headerBuffer[4];
int streamId = ((headerBuffer[5] & 0x7f) << 24) + (headerBuffer[6] << 16) + (headerBuffer[7] << 8) +
headerBuffer[8];
read = await ForceRead(input, buffer, 0, length, cancellationToken);
if (read != length)
{
return;
}
if (isClient)
{
if (type == 1 /*headers*/)
{
bool endHeaders = (flags & (int)Http2FrameFlag.EndHeaders) != 0;
bool padded = (flags & (int)Http2FrameFlag.Padded) != 0;
bool priority = (flags & (int)Http2FrameFlag.Priority) != 0;
System.Diagnostics.Debug.WriteLine("HEADER: " + streamId + " end: " + endHeaders);
int offset = 0;
if (padded)
{
offset = 1;
}
if (priority)
{
offset += 5;
}
int dataLength = length - offset;
if (padded)
{
dataLength -= buffer[0];
}
var headerListener = new MyHeaderListener();
try
{
decoder.Decode(new BinaryReader(new MemoryStream(buffer, offset, dataLength)),
headerListener);
decoder.EndHeaderBlock();
}
catch (Exception)
{
}
}
}
await output.WriteAsync(headerBuffer, 0, headerBuffer.Length, cancellationToken);
await output.WriteAsync(buffer, 0, length, cancellationToken);
/*using (var fs = new System.IO.FileStream($@"c:\11\{connectionId}.{streamId}.dat", FileMode.Append))
{
fs.Write(headerBuffer, 0, headerBuffer.Length);
fs.Write(buffer, 0, length);
}*/
}
}
private static async Task<int> ForceRead(Stream input, byte[] buffer, int offset, int bytesToRead,
CancellationToken cancellationToken)
{
int totalRead = 0;
while (bytesToRead > 0)
{
int read = await input.ReadAsync(buffer, offset, bytesToRead, cancellationToken);
if (read == -1)
{
break;
}
totalRead += read;
bytesToRead -= read;
offset += read;
}
return totalRead;
}
class MyHeaderListener : IHeaderListener
{
public void AddHeader(string name, string value, bool sensitive)
{
Console.WriteLine(name + ": " + value + " " + sensitive);
}
}
}
}
#endif
\ No newline at end of file
...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class HttpHeader public class HttpHeader
{ {
/// <summary>
/// HPACK: Header Compression for HTTP/2
/// Section 4.1. Calculating Table Size
/// The additional 32 octets account for an estimated overhead associated with an entry.
/// </summary>
public const int HttpHeaderOverhead = 32;
internal static readonly Version VersionUnknown = new Version(0, 0); internal static readonly Version VersionUnknown = new Version(0, 0);
internal static readonly Version Version10 = new Version(1, 0); internal static readonly Version Version10 = new Version(1, 0);
...@@ -45,6 +52,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -45,6 +52,13 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public string Value { get; set; } public string Value { get; set; }
public int Size => Name.Length + Value.Length + HttpHeaderOverhead;
public static int SizeOf(string name, string value)
{
return name.Length + value.Length + HttpHeaderOverhead;
}
/// <summary> /// <summary>
/// Returns header as a valid header string. /// Returns header as a valid header string.
/// </summary> /// </summary>
......
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Net.Sockets; using System.Net.Sockets;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
......
using System; using System;
using System.Net; using System.Net;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Net.Sockets; using System.Net.Sockets;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -472,7 +475,6 @@ namespace Titanium.Web.Proxy ...@@ -472,7 +475,6 @@ namespace Titanium.Web.Proxy
/// Gets the connection cache key. /// Gets the connection cache key.
/// </summary> /// </summary>
/// <param name="args">The session event arguments.</param> /// <param name="args">The session event arguments.</param>
/// <param name="isConnect">Is this a CONNECT request.</param>
/// <param name="applicationProtocol"></param> /// <param name="applicationProtocol"></param>
/// <returns></returns> /// <returns></returns>
private async Task<string> getConnectionCacheKey(SessionEventArgsBase args, private async Task<string> getConnectionCacheKey(SessionEventArgsBase args,
......
...@@ -38,4 +38,27 @@ ...@@ -38,4 +38,27 @@
<Reference Include="System.Web" /> <Reference Include="System.Web" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Network\WinAuth\Security\Common.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\LittleEndian.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\Message.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Network\WinAuth\Security\State.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
<Compile Update="Properties\AssemblyInfo.cs">
<ExcludeFromSourceAnalysis>True</ExcludeFromSourceAnalysis>
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
</Compile>
</ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -155,6 +155,35 @@ ...@@ -155,6 +155,35 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h3 id="fields">Fields
</h3>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_HttpHeaderOverhead" data-uid="Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead">HttpHeaderOverhead</h4>
<div class="markdown level1 summary"><p>HPACK: Header Compression for HTTP/2
Section 4.1. Calculating Table Size
The additional 32 octets account for an estimated overhead associated with an entry. </p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const int HttpHeaderOverhead = 32</code></pre>
</div>
<h5 class="fieldValue">Field Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<h3 id="properties">Properties <h3 id="properties">Properties
</h3> </h3>
...@@ -185,6 +214,31 @@ ...@@ -185,6 +214,31 @@
</table> </table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_Size_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Size*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_Size" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Size">Size</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public int Size { get; }</code></pre>
</div>
<h5 class="propertyValue">Property Value</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_Value_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value*"></a> <a id="Titanium_Web_Proxy_Models_HttpHeader_Value_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_Value" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value">Value</h4> <h4 id="Titanium_Web_Proxy_Models_HttpHeader_Value" data-uid="Titanium.Web.Proxy.Models.HttpHeader.Value">Value</h4>
<div class="markdown level1 summary"><p>Header Value.</p> <div class="markdown level1 summary"><p>Header Value.</p>
...@@ -213,6 +267,53 @@ ...@@ -213,6 +267,53 @@
</h3> </h3>
<a id="Titanium_Web_Proxy_Models_HttpHeader_SizeOf_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.SizeOf*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_SizeOf_System_String_System_String_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)">SizeOf(String, String)</h4>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static int SizeOf(string name, string value)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">name</span></td>
<td></td>
</tr>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">value</span></td>
<td></td>
</tr>
</tbody>
</table>
<h5 class="returns">Returns</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.int32">Int32</a></td>
<td></td>
</tr>
</tbody>
</table>
<a id="Titanium_Web_Proxy_Models_HttpHeader_ToString_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString*"></a> <a id="Titanium_Web_Proxy_Models_HttpHeader_ToString_" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString*"></a>
<h4 id="Titanium_Web_Proxy_Models_HttpHeader_ToString" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString">ToString()</h4> <h4 id="Titanium_Web_Proxy_Models_HttpHeader_ToString" data-uid="Titanium.Web.Proxy.Models.HttpHeader.ToString">ToString()</h4>
<div class="markdown level1 summary"><p>Returns header as a valid header string.</p> <div class="markdown level1 summary"><p>Returns header as a valid header string.</p>
......
...@@ -162,7 +162,7 @@ ...@@ -162,7 +162,7 @@
"api/Titanium.Web.Proxy.Models.HttpHeader.html": { "api/Titanium.Web.Proxy.Models.HttpHeader.html": {
"href": "api/Titanium.Web.Proxy.Models.HttpHeader.html", "href": "api/Titanium.Web.Proxy.Models.HttpHeader.html",
"title": "Class HttpHeader | Titanium Web Proxy", "title": "Class HttpHeader | Titanium Web Proxy",
"keywords": "Class HttpHeader Http Header object used by proxy Inheritance Object HttpHeader Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Models Assembly : Titanium.Web.Proxy.dll Syntax public class HttpHeader Constructors HttpHeader(String, String) Initialize a new instance. Declaration public HttpHeader(string name, string value) Parameters Type Name Description String name Header name. String value Header value. Properties Name Header Name. Declaration public string Name { get; set; } Property Value Type Description String Value Header Value. Declaration public string Value { get; set; } Property Value Type Description String Methods ToString() Returns header as a valid header string. Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()" "keywords": "Class HttpHeader Http Header object used by proxy Inheritance Object HttpHeader Inherited Members Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Models Assembly : Titanium.Web.Proxy.dll Syntax public class HttpHeader Constructors HttpHeader(String, String) Initialize a new instance. Declaration public HttpHeader(string name, string value) Parameters Type Name Description String name Header name. String value Header value. Fields HttpHeaderOverhead HPACK: Header Compression for HTTP/2 Section 4.1. Calculating Table Size The additional 32 octets account for an estimated overhead associated with an entry. Declaration public const int HttpHeaderOverhead = 32 Field Value Type Description Int32 Properties Name Header Name. Declaration public string Name { get; set; } Property Value Type Description String Size Declaration public int Size { get; } Property Value Type Description Int32 Value Header Value. Declaration public string Value { get; set; } Property Value Type Description String Methods SizeOf(String, String) Declaration public static int SizeOf(string name, string value) Parameters Type Name Description String name String value Returns Type Description Int32 ToString() Returns header as a valid header string. Declaration public override string ToString() Returns Type Description String Overrides Object.ToString()"
}, },
"api/Titanium.Web.Proxy.Models.ProxyEndPoint.html": { "api/Titanium.Web.Proxy.Models.ProxyEndPoint.html": {
"href": "api/Titanium.Web.Proxy.Models.ProxyEndPoint.html", "href": "api/Titanium.Web.Proxy.Models.ProxyEndPoint.html",
......
...@@ -2070,6 +2070,12 @@ references: ...@@ -2070,6 +2070,12 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.HttpHeader fullName: Titanium.Web.Proxy.Models.HttpHeader.HttpHeader
nameWithType: HttpHeader.HttpHeader nameWithType: HttpHeader.HttpHeader
- uid: Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
name: HttpHeaderOverhead
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_HttpHeaderOverhead
commentId: F:Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
fullName: Titanium.Web.Proxy.Models.HttpHeader.HttpHeaderOverhead
nameWithType: HttpHeader.HttpHeaderOverhead
- uid: Titanium.Web.Proxy.Models.HttpHeader.Name - uid: Titanium.Web.Proxy.Models.HttpHeader.Name
name: Name name: Name
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Name href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Name
...@@ -2083,6 +2089,32 @@ references: ...@@ -2083,6 +2089,32 @@ references:
isSpec: "True" isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.Name fullName: Titanium.Web.Proxy.Models.HttpHeader.Name
nameWithType: HttpHeader.Name nameWithType: HttpHeader.Name
- uid: Titanium.Web.Proxy.Models.HttpHeader.Size
name: Size
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Size
commentId: P:Titanium.Web.Proxy.Models.HttpHeader.Size
fullName: Titanium.Web.Proxy.Models.HttpHeader.Size
nameWithType: HttpHeader.Size
- uid: Titanium.Web.Proxy.Models.HttpHeader.Size*
name: Size
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_Size_
commentId: Overload:Titanium.Web.Proxy.Models.HttpHeader.Size
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.Size
nameWithType: HttpHeader.Size
- uid: Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)
name: SizeOf(String, String)
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_SizeOf_System_String_System_String_
commentId: M:Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String,System.String)
fullName: Titanium.Web.Proxy.Models.HttpHeader.SizeOf(System.String, System.String)
nameWithType: HttpHeader.SizeOf(String, String)
- uid: Titanium.Web.Proxy.Models.HttpHeader.SizeOf*
name: SizeOf
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_SizeOf_
commentId: Overload:Titanium.Web.Proxy.Models.HttpHeader.SizeOf
isSpec: "True"
fullName: Titanium.Web.Proxy.Models.HttpHeader.SizeOf
nameWithType: HttpHeader.SizeOf
- uid: Titanium.Web.Proxy.Models.HttpHeader.ToString - uid: Titanium.Web.Proxy.Models.HttpHeader.ToString
name: ToString() name: ToString()
href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_ToString href: api/Titanium.Web.Proxy.Models.HttpHeader.html#Titanium_Web_Proxy_Models_HttpHeader_ToString
......
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