First working built-in http proxy
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
|
||||
namespace Shadowsocks.Util.Sockets
|
||||
{
|
||||
// Boyer-Moore string search
|
||||
public static class ByteSearch
|
||||
{
|
||||
public class SearchTarget
|
||||
{
|
||||
private readonly byte[] _needle;
|
||||
private readonly int[] _needleCharTable;
|
||||
private readonly int[] _needleOffsetTable;
|
||||
|
||||
public SearchTarget(byte[] needle)
|
||||
{
|
||||
_needle = needle;
|
||||
_needleCharTable = MakeCharTable(needle);
|
||||
_needleOffsetTable = MakeOffsetTable(needle);
|
||||
}
|
||||
|
||||
// Thread-safe
|
||||
public int SearchIn(byte[] haystack, int index, int length)
|
||||
{
|
||||
return IndexOf(haystack, index, length, _needle, _needleOffsetTable, _needleCharTable);
|
||||
}
|
||||
}
|
||||
|
||||
private static int IndexOf(byte[] haystack, int index, int length, byte[] needle, int[] offsetTable, int[] charTable)
|
||||
{
|
||||
|
||||
var end = index + length;
|
||||
for (int i = needle.Length - 1 + index, j; i < end;)
|
||||
{
|
||||
for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// i += needle.length - j; // For naive method
|
||||
i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the mismatched character information.
|
||||
*/
|
||||
private static int[] MakeCharTable(byte[] needle)
|
||||
{
|
||||
const int ALPHABET_SIZE = 256;
|
||||
int[] table = new int[ALPHABET_SIZE];
|
||||
for (int i = 0; i < table.Length; ++i)
|
||||
{
|
||||
table[i] = needle.Length;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
table[needle[i]] = needle.Length - 1 - i;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the scan offset which mismatch occurs.
|
||||
*/
|
||||
private static int[] MakeOffsetTable(byte[] needle)
|
||||
{
|
||||
int[] table = new int[needle.Length];
|
||||
int lastPrefixPosition = needle.Length;
|
||||
for (int i = needle.Length - 1; i >= 0; --i)
|
||||
{
|
||||
if (IsPrefix(needle, i + 1))
|
||||
{
|
||||
lastPrefixPosition = i + 1;
|
||||
}
|
||||
table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
int slen = SuffixLength(needle, i);
|
||||
table[slen] = needle.Length - 1 - i + slen;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is needle[p:end] a prefix of needle?
|
||||
*/
|
||||
private static bool IsPrefix(byte[] needle, int p)
|
||||
{
|
||||
for (int i = p, j = 0; i < needle.Length; ++i, ++j)
|
||||
{
|
||||
if (needle[i] != needle[j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum length of the substring ends at p and is a suffix.
|
||||
*/
|
||||
private static int SuffixLength(byte[] needle, int p)
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = p, j = needle.Length - 1;
|
||||
i >= 0 && needle[i] == needle[j]; --i, --j)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,7 @@ namespace Shadowsocks.Util.Sockets
|
||||
private readonly Encoding _encoding;
|
||||
// private readonly string _delimiter;
|
||||
private readonly byte[] _delimiterBytes;
|
||||
private readonly int[] _delimiterSearchCharTable;
|
||||
private readonly int[] _delimiterSearchOffsetTable;
|
||||
private readonly ByteSearch.SearchTarget _delimiterSearch;
|
||||
private readonly object _state;
|
||||
|
||||
private readonly byte[] _lineBuffer;
|
||||
@@ -78,8 +77,7 @@ namespace Shadowsocks.Util.Sockets
|
||||
throw new ArgumentException("Too small!", nameof(maxLineBytes));
|
||||
}
|
||||
|
||||
_delimiterSearchCharTable = MakeCharTable(_delimiterBytes);
|
||||
_delimiterSearchOffsetTable = MakeOffsetTable(_delimiterBytes);
|
||||
_delimiterSearch = new ByteSearch.SearchTarget(_delimiterBytes);
|
||||
|
||||
_lineBuffer = new byte[maxLineBytes];
|
||||
|
||||
@@ -140,8 +138,7 @@ namespace Shadowsocks.Util.Sockets
|
||||
private void NewPackageRecv()
|
||||
{
|
||||
int i;
|
||||
while ((i = IndexOf(_lineBuffer, _bufferDataIndex, _bufferDataLength, _delimiterBytes, _delimiterSearchOffsetTable,
|
||||
_delimiterSearchCharTable)) != -1)
|
||||
while ((i = _delimiterSearch.SearchIn(_lineBuffer, _bufferDataIndex, _bufferDataLength)) != -1)
|
||||
{
|
||||
var decodeLen = i - _bufferDataIndex;
|
||||
string line = _encoding.GetString(_lineBuffer, _bufferDataIndex, decodeLen);
|
||||
@@ -183,97 +180,5 @@ namespace Shadowsocks.Util.Sockets
|
||||
{
|
||||
_onFinish?.Invoke(_lineBuffer, _bufferDataIndex, _bufferDataLength, _state);
|
||||
}
|
||||
|
||||
#region Boyer-Moore string search
|
||||
|
||||
private static int IndexOf(byte[] haystack, int index, int length, byte[] needle, int[] offsetTable, int[] charTable)
|
||||
{
|
||||
var end = index + length;
|
||||
for (int i = needle.Length - 1 + index, j; i < end;)
|
||||
{
|
||||
for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// i += needle.length - j; // For naive method
|
||||
i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the mismatched character information.
|
||||
*/
|
||||
private static int[] MakeCharTable(byte[] needle)
|
||||
{
|
||||
const int ALPHABET_SIZE = 256;
|
||||
int[] table = new int[ALPHABET_SIZE];
|
||||
for (int i = 0; i < table.Length; ++i)
|
||||
{
|
||||
table[i] = needle.Length;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
table[needle[i]] = needle.Length - 1 - i;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the jump table based on the scan offset which mismatch occurs.
|
||||
*/
|
||||
private static int[] MakeOffsetTable(byte[] needle)
|
||||
{
|
||||
int[] table = new int[needle.Length];
|
||||
int lastPrefixPosition = needle.Length;
|
||||
for (int i = needle.Length - 1; i >= 0; --i)
|
||||
{
|
||||
if (IsPrefix(needle, i + 1))
|
||||
{
|
||||
lastPrefixPosition = i + 1;
|
||||
}
|
||||
table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
|
||||
}
|
||||
for (int i = 0; i < needle.Length - 1; ++i)
|
||||
{
|
||||
int slen = SuffixLength(needle, i);
|
||||
table[slen] = needle.Length - 1 - i + slen;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is needle[p:end] a prefix of needle?
|
||||
*/
|
||||
private static bool IsPrefix(byte[] needle, int p)
|
||||
{
|
||||
for (int i = p, j = 0; i < needle.Length; ++i, ++j)
|
||||
{
|
||||
if (needle[i] != needle[j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum length of the substring ends at p and is a suffix.
|
||||
*/
|
||||
private static int SuffixLength(byte[] needle, int p)
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = p, j = needle.Length - 1;
|
||||
i >= 0 && needle[i] == needle[j]; --i, --j)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ namespace Shadowsocks.Util.Sockets
|
||||
private Socket _activeSocket;
|
||||
|
||||
|
||||
public WrappedSocket() { }
|
||||
|
||||
public WrappedSocket(Socket socket)
|
||||
{
|
||||
_activeSocket = socket;
|
||||
}
|
||||
|
||||
|
||||
public void BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state)
|
||||
{
|
||||
if (_disposed)
|
||||
|
||||
Reference in New Issue
Block a user